8.3 KiB
WP Agentic Writer - Definition of Done
Purpose
This contract prevents the "fix A, break B" cycle by ensuring every change to chat, planning, writing, refinement, context, provider, or cost has explicit ownership and accountability.
Contract Checklist
For every PR touching these domains: chat, planning, writing, refinement, context, provider, cost
1. Storage Layer Declaration
Required: State which storage layer is authoritative for the change.
| State Type | Authoritative Storage |
|---|---|
| Conversation messages | wpaw_conversations.messages (via Context Service) |
| Article outline/plan | post_meta._wpaw_plan (via Context Service) |
| Per-post configuration | post_meta._wpaw_post_config (via Context Service) |
| User preferences | wp_agentic_writer_settings |
| Cost records | wpaw_cost_tracking |
| Image recommendations | wpaw_images |
| Session state | wpaw_conversations |
If the change touches multiple storage layers, explain why and ensure they stay in sync.
1a. Context Service Usage
Required for all generation paths: Use WP_Agentic_Writer_Context_Service as the unified interface.
// Get context (single source of truth)
$context_service = WP_Agentic_Writer_Context_Service::get_instance();
$context = $context_service->get_context($session_id, $post_id);
// Save messages to session table
$context_service->save_messages($session_id, $messages);
// Save plan to post meta
$context_service->save_plan($post_id, $plan);
// Save config to post meta
$context_service->save_post_config($post_id, $config);
Rules:
- Conversation messages → always use
save_messages()oradd_message()(writes to session table) - Plan/Config → use
save_plan()/save_post_config()(writes to post meta) - Legacy
_wpaw_chat_historypost meta → migrate on first access viamigrate_legacy_chat_history()
2. Provider Transparency
Required: Include provider/model metadata in the response.
// Every AI response must include:
$result = [
'content' => '...',
'provider' => 'openrouter', // actual provider used
'model' => 'anthropic/claude-3.5-haiku', // actual model used
'cost' => 0.0025,
'warnings' => [] // any issues (fallback used, etc)
];
3. Cost Record Integrity
Required: Every API request must update cost records intentionally.
- Successful calls → record actual cost
- Failed calls → record attempt with error status
- Skipped calls → no record needed
- Never silently fail to record costs
4. Workflow Test Requirement
Required: Test at least one complete workflow path.
Minimum paths to test:
- Chat → Plan → Write (happy path)
- Write → Stop → Resume (pause/resume)
- Plan → Clear Context → New Plan (context reset)
For each path, verify:
- State persists correctly
- Cost records are accurate
- Errors are handled gracefully
5. No Double Source of Truth
Required: The same state must not exist in two places.
- If session table is authoritative, don't also trust post meta for the same data
- If you copy data for performance, document the sync mechanism
- If two sources diverge, one must win (document which)
Storage Layer Map
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND (sidebar.js) │
│ React State ← localStorage ← Session Table ← Post Meta │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ BACKEND (PHP) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Sessions │ │ Post Meta │ │ Settings/Cost │ │
│ │ wpaw_conv │ │ _wpaw_plan │ │ wpaw_cost_tracking │ │
│ │ │ │ _wpaw_* │ │ wp_agentic_writer_* │ │
│ │ Authority: │ │ Authority: │ │ Authority: │ │
│ │ Messages │ │ Plan/Config │ │ Settings/Costs │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Priority Rules:
wpaw_conversationsis authoritative for conversation messagespost_metais authoritative for article plan and per-post configwpaw_cost_trackingis authoritative for usage costswp_agentic_writer_settingsis authoritative for plugin settings
Error Handling Contract
For AI/Provider Errors
// Always return meaningful errors, not silent failures
if ( is_wp_error( $result ) ) {
return [
'success' => false,
'error_code' => $result->get_error_code(),
'error_message' => $result->get_error_message(),
'provider' => $actual_provider_used ?? 'unknown',
'can_retry' => is_retryable_error( $result )
];
}
For Database Errors
// Tables must exist before operations; verify and create if needed
$image_manager->ensure_tables(); // Call this before any DB operation
if ( is_wp_error( $check ) ) {
return $check; // Return WP_Error with clear message
}
For Validation Errors
// Validate early, fail clearly
if ( empty( $post_id ) ) {
return new WP_Error( 'missing_post_id', 'Post ID is required', 400 );
}
Provider Selection Contract
Explicit Fallback
If a provider fails and you fall back to another:
- Log the fallback with both provider names
- Include
warnings: ['Provider X unavailable, fell back to Y']in response - UI must show actual provider used, not selected provider
Provider Health Check
Before expensive operations, optionally verify provider is reachable:
// In provider-manager.php, expose health status
public static function get_provider_health( $provider_name ) {
$provider = self::get_provider_instance( $provider_name, 'chat' );
if ( ! $provider || ! $provider->is_configured() ) {
return ['status' => 'unconfigured'];
}
// Optional: test reachability
return ['status' => 'ready'];
}
Migration Safety Contract
When adding new database tables or fields:
- Always use
CREATE TABLE IF NOT EXISTS - Provide migration for existing installations
- Handle missing tables gracefully (create on demand)
- Version each table independently
Security Contract
Session Access
- Every session endpoint must verify ownership
- Users can only access their own sessions
- For post-linked sessions, verify
current_user_can('edit_post', $post_id)
Input Validation
- Sanitize all inputs before database operations
- Use WordPress sanitization functions
- Never trust user-provided data
Output Escaping
- All output to frontend must be escaped appropriately
- Use
wp_json_encode()for JSON - Use
esc_html(),esc_attr()for text
Testing Requirements
Before Merging
- PHP syntax check passes
- JS syntax check passes
- All new functions have docblocks
- No hardcoded credentials or API keys
- Error paths are tested (even if manually)
For New Features
- At least one workflow path tested end-to-end
- Error handling documented
- Cost implications considered
- Storage layer declaration written
Changelog Policy
When making changes, update CHANGELOG.md with:
## [Unreleased]
### Added
- Feature description
### Changed
- Behavior change
### Fixed
- Bug fix description
### Security
- Security fix description
Format: Keep unreleased at top, use semantic versioning for releases.