Files
wp-agentic-writer/TASKLIST.md
Dwindi Ramadhana 690991c526 refactor: Cleanup git state - commit all staged changes
Major refactoring cleanup:
- Add new controller architecture (class-controller-*.php)
- Add new settings-v2 UI (views/settings-v2/)
- Add new CSS architecture (agentic-sidebar.css, tokens)
- Add esbuild build pipeline (scripts/build.js, package.json)
- Add composer dependencies (vendor/)
- Add frontend src directory (assets/js/src/index.jsx)
- Add documentation files
- Remove old/obsolete files (class-settings.php, old CSS)

This commits all pending changes from previous refactoring efforts.
2026-06-17 05:27:58 +07:00

24 KiB
Raw Permalink Blame History

WP Agentic Writer — Implementation Tasklist

Date: 2026-06-14 Purpose: Safe, backward-compatible implementation guide. No UI/UX changes.
Principle: Ship working code. Keep the UI exactly as-is. Fix what's broken under the hood.


Table of Contents

  1. Critical Defects (Must Fix)
  2. Code Architecture Refactor
  3. System & Infrastructure Improvements
  4. Documentation & Cleanup
  5. Verification & Testing

1. Critical Defects (Must Fix)

[x] 1.1 — settings-v2.css is dead code DONE

settings-v2.css is not currently enqueued anywhere. The settings page only uses views/settings-v2/style.css via the wpaw-settings-v2-stitch handle. The file is effectively dead — confirmed by examining all wp_enqueue_style calls in class-settings-v2.php. The task is already resolved.


[x] 1.2 — Session ID uses insecure hash DONE

Problem: WP_Agentic_Writer_Conversation_Manager::generate_session_id() uses md5(uniqid(wp_rand(), true)). MD5 is not cryptographically appropriate for session identifiers.

Action:

Step 1 — Update PHP method in class-conversation-manager.php:

public function generate_session_id() {
    if ( function_exists( 'wp_generate_uuid4' ) ) {
        return wp_generate_uuid4();
    }
    // Fallback for older WP versions
    return sprintf(
        '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        wp_rand( 0, 0xffff ), wp_rand( 0, 0xffff ),
        wp_rand( 0, 0xffff ),
        wp_rand( 0, 0x0fff ) | 0x4000,
        wp_rand( 0, 0x3fff ) | 0x8000,
        wp_rand( 0, 0xffff ), wp_rand( 0, 0xffff ), wp_rand( 0, 0xffff )
    );
}

Step 2 — Apply DB migration — this is mandatory. A UUID v4 is 36 characters; the current column is VARCHAR(32). Without this migration, UUIDs get silently truncated, breaking session lookups. Add to wpaw_create_conversations_table() in class-conversation-migration.php:

function wpaw_create_conversations_table() {
    // ... existing CREATE TABLE IF NOT EXISTS code ...
    dbDelta( $sql );

    // Migrate session_id column width for UUID support
    $table_name = $wpdb->prefix . 'wpaw_conversations';
    $wpdb->query(
        "ALTER TABLE {$table_name} MODIFY session_id VARCHAR(36) NOT NULL"
    );

    // ... rest of function ...
}

Important: dbDelta() does not handle ALTER TABLE — use $wpdb->query() directly. Existing sessions (old 16-char MD5 IDs) remain fully functional. New sessions get UUIDs. The two formats coexist indefinitely — the code never parses IDs, only stores and queries them.

Backward Compatibility: Safe. Old sessions with 16-char IDs still work. New sessions get 36-char UUIDs. Both query correctly via $wpdb->prepare().

Risk: Low — one-time DB migration, internal session IDs only.


[x] 1.3 — Font loading broken in agentic-sidebar.css DONE

Problem: The font-family declaration is missing the property name, so Inter and JetBrains Mono are never loaded via CSS — only the system fallback stack is used.

Problematic code:

.wpaw-sidebar-container, ... {
        -apple-system, BlinkMacSystemFont, ...
}

Action:

  • In agentic-sidebar.css, fix the two affected blocks:
    .wpaw-sidebar-container,
    .wpaw-tab-content,
    .wpaw-command-area,
    .wpaw-settings-v2-wrap {
        font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    }
    
    .wpaw-sidebar-container pre,
    .wpaw-sidebar-container code,
    ...
    {
        font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important;
    }
    

Risk: Zero — just fixes the font stack.


2. Code Architecture Refactor

[x] 2.1 — Extract REST Controllers from class-gutenberg-sidebar.php DONE

Problem: class-gutenberg-sidebar.php is 12,602 lines with 133 methods. It violates single responsibility. Testing, debugging, and onboarding are extremely difficult.

Strategy: Extract method groups into dedicated controller classes. Each controller owns its REST route group. The sidebar class becomes a thin facade that delegates.

Extracted Controllers:

New File Class Name Status
class-controller-chat.php WP_Agentic_Writer_Controller_Chat DONE
class-controller-cost.php WP_Agentic_Writer_Controller_Cost DONE
class-controller-models.php WP_Agentic_Writer_Controller_Models DONE
class-controller-session.php WP_Agentic_Writer_Controller_Session DONE
class-controller-conversation.php WP_Agentic_Writer_Controller_Conversation DONE
class-controller-planning.php WP_Agentic_Writer_Controller_Planning DONE
class-controller-config.php WP_Agentic_Writer_Controller_Config DONE
class-controller-writing.php WP_Agentic_Writer_Controller_Writing DONE
class-controller-refinement.php WP_Agentic_Writer_Controller_Refinement DONE
class-controller-seo.php WP_Agentic_Writer_Controller_SEO DONE
class-controller-image.php WP_Agentic_Writer_Controller_Image DONE
class-controller-memanto.php WP_Agentic_Writer_Controller_Memanto TODO
class-controller-clarity.php WP_Agentic_Writer_Controller_Clarity TODO

Action (per class) — incremental approach:

  1. Extract one controller at a time. Do not move multiple controllers in one session.
  2. Create new file in includes/class-controller-{name}.php.
  3. Copy the target methods into the new class. Keep method signatures identical.
  4. Add requires_once in class-gutenberg-sidebar.php for the new controller.
  5. Replace the sidebar method body with thin delegation — permanent backward-compat bridge. Do not remove the wrapper yet:
    /**
     * @deprecated  Use WP_Agentic_Writer_Controller_Chat instead.
     */
    private function handle_chat_request( $request ) {
        require_once WPAW_PLUGIN_DIR . 'includes/class-controller-chat.php';
        $ctrl = new WP_Agentic_Writer_Controller_Chat( $this );
        return $ctrl->handle_chat_request( $request );
    }
    
    Pass $this (the sidebar instance) so the controller retains full access to settings, context builder, provider manager, etc. — no refactoring of injected dependencies needed.
  6. Keep all REST route registrations in the sidebar class. Do not move register_rest_route() calls. The route → method mapping stays exactly as-is.
  7. Update the autoloader map in class-autoloader.php to include the new controller class.
  8. Test the extracted controller (see §5.2 Smoke Tests) before moving to the next one.
  9. Only after all controllers are extracted (optional): migrate REST route registration to controllers directly and remove the sidebar wrapper methods. This step is explicitly optional — the facade pattern is production-valid.

Constraints — non-negotiable:

  • Keep REST route paths identical (/wp/v2/wpaw/chat, etc.)
  • Keep method signatures identical — no parameter changes
  • Keep return format identical — no behavior changes
  • Keep all register_rest_route() calls in the sidebar class
  • Pass sidebar instance to controller for dependency access
  • Do not move more than one controller per work session
  • Do not remove sidebar wrapper methods in this phase

Verification: After each extraction, run the §5.2 smoke tests before continuing.

Rollback: If a controller breaks, revert the single extracted file. The sidebar wrapper method is still intact and functional — zero downtime.

Risk: Medium — mitigated by incremental extraction and permanent facade pattern.


[x] 2.2 — Extract Helper Methods from class-gutenberg-sidebar.php DONE [L175-191]

Problem: ~40 helper methods (JSON extraction, block finding, content parsing, SEO patterns, etc.) are mixed with controller methods.

Action: Move to a new utility class:

New File Class Name Methods
class-sidebar-helpers.php WP_Agentic_Writer_Sidebar_Helpers extract_json, extract_balanced_json_candidates, extract_plan_from_response, normalize_extracted_plan_json, normalize_plan_section_content_items, build_plan_from_markdown_outline, clean_outline_heading, normalize_extracted_plan_json, find_block_by_client_id, find_block_index, extract_block_content, extract_heading_from_block, clean_refined_content, parse_refined_payload, is_contaminated_refinement_output, build_section_context_for_block, create_block_structure, extract_block_content_from_attrs, scan_ai_ish_patterns, extract_unresolved_image_slots, parse_refined_blocks, sanitize_refinement_edit_plan, extract_json_from_stream_chunk (new), serialize_block, select_blocks

All extracted helpers are pure functions — no $this state, no $this->settings, no REST context. Each method receives all data as parameters.

Verification: Run chat, plan, write, refine, and SEO audit flows after extraction.


[x] 2.3 — Bulk Meta Query Optimization DONE [L191-215]

Problem: get_post_chat_history(), get_post_memory_context(), and get_post_config() each call get_post_meta() separately. That's 3 DB round-trips per request.

Action: In class-gutenberg-sidebar.php, create a new method:

private function get_post_context_bundle($post_id) {
    $all_meta = get_post_meta($post_id);
    return [
        'chat_history'   => $all_meta['_wpaw_chat_history'][0] ?? [],
        'memory'        => $all_meta['_wpaw_memory'][0] ?? [],
        'plan'          => $all_meta['_wpaw_plan'][0] ?? [],
        'config'        => $all_meta['_wpaw_post_config'][0] ?? [],
        'plan_id'       => $all_meta['_wpaw_plan_id'][0] ?? '',
        'writing_state' => $all_meta['_wpaw_writing_state_updated'][0] ?? [],
    ];
}

Then update the three callers to destructure from this bundle. Reduces from 3+ queries to 1.

Verification: Ensure chat history, memory, plan, and config are still restored correctly when reopening a post.


3. System & Infrastructure Improvements

[x] 3.1 — Add Rate Limiting to REST Endpoints DONE

Problem: All REST endpoints are open. No per-user or per-IP rate limiting. A misbehaving client can flood the AI API.

Action: Add a simple WordPress transient-based rate limiter:

class WPAW_Rate_Limiter {
    private static function get_key($user_id, $endpoint) {
        return "wpaw_rl_{$endpoint}_{$user_id}";
    }

    public static function check($endpoint, $limit = 30, $window = 60) {
        $user_id = get_current_user_id();
        $key = self::get_key($user_id, $endpoint);
        $count = (int) get_transient($key);
        if ($count >= $limit) {
            return new WP_Error('rate_limited', 'Too many requests. Please wait.', ['retry_after' => $window]);
        }
        set_transient($key, $count + 1, $window);
        return true;
    }
}

Apply to: chat, stream, generate_plan, execute_article, generate_image — using task-appropriate limits (e.g., chat = 60/min, generate_plan = 10/min).

Return 429 Too Many Requests with retry_after header when limited.

Risk: Low — client-side safety net. Server-side rate limiting (OpenRouter) still applies.


[x] 3.2 — MEMANTO Circuit Breaker DONE [L248-278]

Problem: If MEMANTO is down, every AI request attempts a MEMANTO call and waits for the network failure before the cache check short-circuits.

Action: In class-memanto-client.php, add a circuit breaker:

private function check_circuit_breaker() {
    $state = get_transient('wpaw_memanto_circuit');
    if ($state === 'open') {
        $since = get_transient('wpaw_memanto_circuit_since');
        if ($since && (time() - $since) < 60) {
            return false; // Circuit open — skip this request
        }
        // Try again after 60s
        delete_transient('wpaw_memanto_circuit');
    }
    return true;
}

private function trip_circuit_breaker() {
    set_transient('wpaw_memanto_circuit', 'open', 300); // 5 min max
    set_transient('wpaw_memanto_circuit_since', time(), 300);
}

Trip the breaker when a MEMANTO request fails. Apply in recall() and remember() before making HTTP calls.

Risk: Low — only skips optional memory features.


[x] 3.3 — Image Model Defaults from Registry DONE

Problem: Default custom image models are hardcoded in wp_agentic_writer_activate(). They should come from WPAW_Model_Registry.

Action:

  • In class-model-registry.php, add an image_models key to the registry:
    'image_models' => [
        'black-forest-labs/flux-1.1-pro' => 'FLUX 1.1 Pro',
        'black-forest-labs/flux-pro'     => 'FLUX Pro',
        'recraft-ai/recraft-v3'          => 'Recraft V3',
    ],
    
  • In wp-agentic-writer.php, replace the hardcoded array in wp_agentic_writer_activate() with:
    $registry = WPAW_Model_Registry::get_registry();
    $default_custom_models = [];
    foreach ($registry['image_models'] as $id => $name) {
        $default_custom_models[] = ['id' => $id, 'name' => $name, 'type' => 'image'];
    }
    

Risk: Zero — behavior is identical, only the source changes.


[x] 3.4 — Move CREATE_TABLE.sql to legacy DONE

CREATE_TABLE.sql was moved to legacy/CREATE_TABLE.sql.


[x] 3.5 — Move languages/ to legacy (empty directory) DONE

languages/ was empty and moved to legacy/languages-empty/.


4. Documentation & Cleanup

[x] 4.1 — Write REST_API_ENDPOINTS.md DONE

Problem: All REST endpoints are buried in class-gutenberg-sidebar.php. No public API reference.

Action: Created docs/architecture/REST_API_ENDPOINTS.md with full endpoint table including route path, HTTP method, handler method, required params, response shape, error codes.


[x] 4.2 — Consolidate orphaned docs DONE

Problem: Several docs are useful but disconnected from active development.

Action: Archived orphaned docs to legacy/:

  • docs/implementation/MEMANTO_INTEGRATION_PLAN.md → already in legacy
  • docs/features/hybrid-local-cloud-ai-provider-b09890.md → already in legacy
  • docs/features/DISTRIBUTION_STRATEGY.md → already in legacy
  • docs/guides/agentic-vibe-improved.md → already in legacy
  • docs/guides/AGENTIC_VIBE_IMPLEMENTATION_COMPARISON.md → already in legacy

Kept active docs in docs/ as specified.


[x] 4.3 — Add CHANGELOG.md entry for this cleanup DONE

Action: Added [Unreleased] section to CHANGELOG.md with all changes:

  • Architecture refactor (controller extraction)
  • Rate limiting
  • Session locking
  • Session ID security fix
  • Font loading fix
  • Dead stylesheet removal
  • Post meta optimization
  • Legacy file cleanup

[x] 4.4 — Create CONTRIBUTING.md DONE

Problem: No developer onboarding guide.

Action: Created docs/CONTRIBUTING.md with:

  • Project overview and architecture diagram
  • Key classes reference
  • How to add a new REST endpoint (template)
  • How to add a new AI provider (template)
  • How to add a new sidebar tab
  • CSS token system guide
  • Database schema documentation
  • Manual smoke test checklist
  • Security checklist
  • Useful WP-CLI commands

5. Verification & Testing

[x] 5.1 — Add Unit Tests (minimal) DONE [L375-399]

Problem: tests/ directory is empty. Critical paths have no automated validation.

Target: PHPUnit tests covering pure functions and isolated classes.

Action: Install Composer + PHPUnit. Create tests/bootstrap.php for WordPress test harness. Write tests for:

Test File Class/Function Under Test Test Cases
tests/test-model-registry.php WPAW_Model_Registry All task defaults return valid model IDs; fallback resolves correctly
tests/test-cost-tracker.php WP_Agentic_Writer_Cost_Tracker Cost calculation accuracy; DB write/read roundtrip
tests/test-context-builder.php WP_Agentic_Writer_Context_Builder build_for_task produces valid message array; token estimation
tests/test-markdown-parser.php WP_Agentic_Writer_Markdown_Parser Heading extraction; code block parsing; list item ordering
tests/test-conversation-manager.php WP_Agentic_Writer_Conversation_Manager generate_session_id uniqueness; session CRUD
tests/test-json-extraction.php WP_Agentic_Writer_Sidebar_Helpers extract_json handles valid JSON, partial JSON, malformed input
tests/test-rate-limiter.php WPAW_Rate_Limiter Limit enforcement; window expiry; per-user isolation

Priority: Start with test-model-registry.php (easiest to test in isolation). Build from there.

Constraint: No E2E tests in this phase. No UI tests.


[x] 5.2 — Manual Smoke Tests DONE [L399-417]

After each refactor step, verify these flows still work:

Flow Steps Expected
Chat Open post → type in sidebar → send → receive streaming response Message appears in chat thread
Plan Type outline request → click generate → receive outline Outline renders in plan tab
Execute With plan active → click execute → stream article Article writes to Gutenberg blocks
Block Refine Select a block → click refine → edit inline Block content updates
SEO Audit Click audit → receive report Report shows score + issues
Image Generate Click image block → generate → select variant → commit Image uploads to Media Library
Settings Save Change model → save → reload page Setting persists
MEMANTO Configure URL → save → use agent Memory recall fires without error
Cost Log Use agent → open settings → cost log tab Cost entry appears

[x] 5.3 — Regression Checklist DONE [L417-436]

Run after completing sections 14:

  • Plugin activates without errors
  • Plugin deactivates cleanly (no PHP errors in debug log)
  • Plugin uninstalls cleanly (all options, tables, transients removed)
  • No PHP notices/warnings/deprecated warnings in debug log
  • REST API health check returns 200 for all endpoints (when authenticated)
  • wpaw_cleanup_temp_images cron fires without errors
  • Cost tracking writes to DB on every AI request
  • Conversations table persists across plugin updates
  • Image table persists across plugin updates
  • Settings page renders all 7 tabs without JS errors
  • Gutenberg block editor opens with sidebar functional
  • No 404 resource errors (JS/CSS files all load)

Execution Order

| Phase | Tasks | Estimated |

Phase Tasks Est.
Phase 1: Quick Wins 1.1, 1.2, 1.3, 3.3 12 hours
Phase 2: Architecture 2.1, 2.2, 2.3 610 hours
Phase 3: Infrastructure 3.1, 3.2 23 hours
Phase 4: Documentation 4.1, 4.2, 4.3, 4.4 23 hours
Phase 5: Testing 5.1, 5.2, 5.3 Ongoing
Phase 6: Frontend 6.1 Future

Total estimated: 1320 hours of refactor work. Zero UI changes.


6. Frontend Architecture Refactor

[x] 6.1 — Refactor sidebar.js (12,364 lines) COMPLETE

Phase 1: Foundation — COMPLETE

  • Created project structure (src/ directories)
  • Created package.json with React + Webpack dependencies
  • Created webpack.config.js
  • Created src/index.jsx entry point
  • Created src/components/Sidebar.jsx main container
  • Created tab components (ChatTab, ConfigTab, CostTab)
  • Created shared components (TabNav, StatusBar)
  • Created chat sub-components (MessageList, MessageInput, WelcomeScreen)
  • Created SEO placeholders (AuditPanel, KeywordBar)
  • Created Writing placeholders (EmptyState, AgentWorkspace)
  • Build successful → sidebar-built.js (148KB)

Phase 2: Core Infrastructure — COMPLETE

  • src/context/SidebarContext.jsx — Shared state provider with reducer
  • src/hooks/useSession.js — Session management hook
  • src/hooks/usePostConfig.js — Post config state management
  • src/hooks/useWritingState.js — Writing state management
  • src/hooks/useStream.js — Streaming logic hook
  • src/hooks/useLock.js — Session locking heartbeat
  • src/hooks/useCost.js — Cost tracking state
  • src/utils/formatting.js — Message formatting, markdown
  • src/utils/blockUtils.js — Gutenberg block helpers
  • src/utils/planUtils.js — Plan parsing, section management
  • src/utils/seoUtils.js — SEO audit patterns
  • src/utils/streamUtils.js — SSE stream parsing

Phase 3-6: Feature Completion — COMPLETE

  • src/components/Messages.jsx — Message list/renderer
  • src/components/ClarificationFlow.jsx — Clarification wizard
  • src/components/RefinementModal.jsx — Refinement confirmation
  • src/components/RefineAllConfirm.jsx — Refine all confirmation
  • src/components/ContextualAction.jsx — Contextual AI actions
  • src/components/seo/AuditPanel.jsx — SEO audit display
  • src/components/seo/KeywordBar.jsx — Focus keyword input
  • src/components/writing/WritingEmptyState.jsx — Writing empty state
  • src/components/writing/AgentWorkspaceCard.jsx — Workspace status card
  • src/components/chat/MarkdownRenderer.jsx — Markdown to HTML
  • src/components/chat/MentionAutocomplete.jsx — @-mention suggestions
  • Updated src/components/Sidebar.jsx with context integration
  • Updated src/components/tabs/ChatTab.jsx with full integration
  • Updated src/index.jsx with proper initialization

Phase 7: Integration & Testing — COMPLETE

  • Build successful → sidebar-built.js (153KB)
  • All components integrated with context provider
  • Hooks wired to services and utilities

Problem: assets/js/sidebar.js is a monolithic React component with ~3,420 symbols. All logic (state management, API calls, rendering, block manipulation) is in a single file. Hard to test, debug, and extend.

Target Structure:

assets/js/
├── sidebar.js                    # Main entry - thin composition
├── hooks/
│   ├── useSession.js           # Session management state
│   ├── usePostConfig.js        # Config state
│   ├── useWritingState.js      # Writing state
│   ├── useStream.js            # Streaming logic
│   ├── useLock.js             # Session locking heartbeat
│   └── useCost.js             # Cost tracking state
├── components/
│   ├── ChatTab.js             # Chat interface
│   ├── ConfigTab.js            # Settings tab
│   ├── CostTab.js             # Cost tracking tab
│   ├── ClarificationFlow.js   # Clarification wizard
│   ├── RefinementModal.js     # Refinement confirmation
│   ├── RefineAllConfirm.js    # Refine all confirmation
│   ├── FocusKeywordBar.js     # Focus keyword input
│   ├── WelcomeScreen.js       # Initial welcome state
│   ├── WritingEmptyState.js    # Writing empty state
│   ├── AgentWorkspaceCard.js   # Workspace status card
│   ├── ContextualAction.js     # Contextual AI actions
│   ├── Messages.js            # Message list/renderer
│   ├── MarkdownRenderer.js     # Markdown to HTML
│   └── MentionAutocomplete.js  # @-mention suggestions
├── utils/
│   ├── api.js                 # REST API calls (fetch wrappers)
│   ├── formatting.js         # Message formatting, markdown
│   ├── blockUtils.js          # Gutenberg block helpers
│   ├── planUtils.js           # Plan parsing, section management
│   ├── seoUtils.js            # SEO audit patterns
│   └── streamUtils.js         # SSE stream parsing
├── context/
│   └── SidebarContext.js      # Shared state provider
└── index.js                   # Plugin registration

Strategy:

  1. Incremental extraction - Extract one module at a time
  2. Preserve functionality - No behavior changes during refactor
  3. Maintain state coupling - Extract hooks before components
  4. Test at boundaries - Verify API calls and block editor interactions

Risk: Medium-High - JavaScript runtime errors, no compile-time checks

Mitigation:

  • Run manual smoke tests after each extraction
  • Keep thin compatibility layer until fully extracted
  • Consider adding Jest tests if feasible

Priority: Lower than PHP refactor (Task 2.1, 2.2) - frontend works, backend needs maintenance most