Skip to content

ADR-0018 — Durable Work Orchestration, Semantic Activity Feed and Runtime WebUI

Repository: agent-adk-wpdoctor
Version: 1.0
Status: Proposed for immediate adoption
Type: Amendment to ADR-0017
Date: 2026-09-09
Supersedes: No ADR in full
Amends: ADR-0017 (ADR-0001-wpdoctor-v1.md en el repositorio de producto)


1. Purpose

This ADR extends ADR-0017 with four foundational capabilities that MUST become part of WPDoctor architecture before complex multi-agent operations are implemented:

  1. Durable Work Orchestration
  2. Per-tenant SQLite operational persistence
  3. Human-readable Semantic Activity Feed
  4. Built-in operator WebUI

The objective is to ensure WPDoctor does not become a collection of ephemeral ADK agents whose internal work disappears into prompts, stdout or framework session state.

WPDoctor MUST provide durable, observable, resumable and human-comprehensible autonomous work.

The resulting architecture is:

Customer / Operator
        │
        ▼
WPDoctor Manager
        │
        ▼
Work Planner
        │
        ▼
Persistent TaskBoard
        │
        ▼
Task Scheduler
        │
 ┌──────┼────────┬─────────┐
 ▼      ▼        ▼         ▼
Linux   PHP      DB      WordPress
Agent   Agent    Agent      Agent
 │       │        │         │
 └───────┴────────┴─────────┘
        │
        ▼
Operations
        │
        ▼
Policy Engine
        │
        ▼
Tools / Adapters
        │
        ▼
SSH
        │
        ▼
Customer Infrastructure

Parallel planes:

SQLite
├── WorkPlans
├── Tasks
├── Incidents
├── Inventory
├── Evidence metadata
├── Activity Events
├── Audit
└── Approvals

Hindsight
└── Long-term semantic tenant memory

OpenTelemetry
└── Technical observability

WebUI
└── Human operational observability

2. Architectural Decision

WPDoctor v1 SHALL use the following persistence and coordination model:

1 tenant
    =
1 active WPDoctor runtime
    =
1 Docker container / Kubernetes Pod
    =
1 persistent local SQLite database

The canonical database path SHALL initially be:

/data/wpdoctor.db

The runtime persistent area SHALL be:

/data/
├── wpdoctor.db
├── artifacts/
├── workspace/
└── runtime/

The initial Kubernetes model SHALL assume:

replicas = 1
PVC = ReadWriteOnce

Two active WPDoctor runtimes MUST NOT concurrently open the same SQLite database.


3. Rationale for SQLite

SQLite is selected for WPDoctor v1 because the initial deployment model already provides natural single-runtime tenant isolation.

It offers:

  • zero external database dependency;
  • simple tenant deployment;
  • local durability;
  • easy backup;
  • easy debugging;
  • easy migration between hosts;
  • sufficient concurrency for one runtime;
  • excellent fit for early dogfooding and pilots.

This decision is intentionally temporary but not disposable.

All persistence MUST be abstracted behind repository interfaces so PostgreSQL can replace SQLite without modifying agents, operations, policies or domain semantics.


4. SQLite Configuration

Every runtime MUST configure SQLite with at minimum:

PRAGMA journal_mode=WAL;
PRAGMA foreign_keys=ON;
PRAGMA busy_timeout=5000;
PRAGMA synchronous=NORMAL;

The exact synchronous policy MAY become configurable later.

Database connections MUST use short transactions.

The following pattern is forbidden:

BEGIN TRANSACTION
    ↓
LLM reasoning
    ↓
SSH call
    ↓
another LLM call
    ↓
COMMIT

Transactions MUST contain only short database work.

Correct pattern:

claim task
COMMIT

external work / reasoning / SSH

save result
COMMIT

5. Persistence Boundary

No specialist agent may access SQLite directly.

Forbidden:

sqlite.execute(...)

inside:

agents/
operations/
skills/

Database access SHALL happen through application-level repositories/services.

Required abstractions:

TenantRepository
HostRepository
SiteRepository
InventoryRepository

IncidentRepository
EvidenceRepository

WorkPlanRepository
TaskRepository
TaskAttemptRepository

ApprovalRepository

ActivityRepository
AuditRepository

ArtifactRepository

Conceptual example:

class TaskRepository(Protocol):
    async def create(...)
    async def get(...)
    async def list(...)
    async def claim(...)
    async def heartbeat(...)
    async def complete(...)
    async def fail(...)
    async def block(...)
    async def cancel(...)
    async def release_expired_leases(...)

A future implementation may provide:

SQLiteTaskRepository
PostgresTaskRepository

without affecting calling code.


6. Revised Orchestration Model

ADR-0017 described:

Manager
  ↓
Operations

This ADR extends that model.

Complex work SHALL use:

Manager
   ↓
Work Planner
   ↓
WorkPlan
   ↓
TaskBoard
   ↓
Scheduler
   ↓
Specialists / Operations

Simple operations MAY still execute synchronously.


7. Direct Execution vs WorkPlan

The runtime SHALL support two execution classes.

7.1 Direct Operation

Appropriate for:

  • simple inspection;
  • single target;
  • short deterministic action;
  • no dependencies;
  • no parallelization;
  • no approval delay;
  • no need for resumability.

Example:

"Show disk usage on srv01."

7.2 Durable WorkPlan

SHALL be used when one or more of the following applies:

  • multiple servers;
  • multiple sites;
  • multiple specialists;
  • dependencies;
  • fan-out/fan-in;
  • human approval;
  • retries;
  • potentially long execution;
  • autonomous multi-step remediation;
  • background/resumable work;
  • operation expected to survive runtime restart.

Examples:

Audit 150 WordPress sites.

Investigate intermittent 502 errors.

Update all safe WordPress plugins across the estate.

Perform a complete performance analysis.

Migrate sites from PHP 8.2 to PHP 8.3.

The exact threshold MUST NOT be based solely on elapsed time.

It is a semantic orchestration decision.


8. Domain Model: WorkPlan

A WorkPlan represents durable decomposition of an objective.

Required fields:

id:
tenant_id:

incident_id: optional

title:
objective:

status:

created_by:
created_at:
updated_at:

budget:
  max_tasks:
  max_parallel_tasks:
  max_attempts_per_task:
  max_model_calls:
  max_tool_calls:
  max_runtime_seconds:
  max_cost: optional

current_summary:

started_at:
completed_at:
cancelled_at:

Recommended status values:

PLANNING
READY
RUNNING
WAITING_APPROVAL
BLOCKED
COMPLETED
FAILED
CANCELLED
PAUSED

9. Domain Model: Task

A Task represents one schedulable unit of work.

Required model:

id:
tenant_id:
workplan_id:
incident_id: optional

type:
title:
description:

status:
priority:

required_role:
required_capabilities: []

target:
  host_id: optional
  site_id: optional
  service_id: optional

risk_level:

claimed_by: optional
lease_until: optional

attempt_count:
max_attempts:

current_summary:
next_action:

created_by:
created_at:
updated_at:
started_at:
finished_at:

Optional metadata MAY be stored in JSON.

Fields involved in scheduling MUST remain first-class indexed columns.


10. Task States

Canonical Task state model:

BACKLOG
   ↓
READY
   ↓
CLAIMED
   ↓
RUNNING
   ↓
REVIEW
   ↓
DONE

Exceptional states:

BLOCKED
WAITING_APPROVAL
FAILED
CANCELLED

Transitions MUST be validated by domain logic.

Arbitrary state mutation is forbidden.

Example valid transitions:

BACKLOG → READY
READY → CLAIMED
CLAIMED → RUNNING
RUNNING → REVIEW
REVIEW → DONE

RUNNING → BLOCKED
RUNNING → WAITING_APPROVAL
RUNNING → FAILED

CLAIMED → READY
    when lease expires

FAILED → READY
    when retry policy permits

11. Dependencies

Task dependencies SHALL be first-class persistent records.

Table:

task_dependencies

Fields:

task_id
depends_on_task_id
dependency_type
created_at

Initial dependency semantics:

REQUIRES_SUCCESS
REQUIRES_COMPLETION

A Task SHALL remain blocked from scheduling until dependencies are satisfied.


12. Fan-Out / Fan-In

The planner MUST support workload expansion.

Example:

Audit estate
     │
     ▼
Discover inventory
     │
     ▼
     fan-out
 ┌────┼────┬────┐
 ▼    ▼    ▼    ▼
srv1 srv2 srv3 srv4
 │    │    │    │
 └────┴────┴────┘
      │
      ▼
    fan-in
      │
      ▼
Aggregate
      │
      ▼
Review

Example:

5 hosts
73 sites

may materialize into dozens of independent tasks.

The Manager SHALL NOT need all task contents inside its active LLM context simultaneously.


13. Scheduler

WPDoctor SHALL implement an internal TaskScheduler.

Responsibilities:

  • find runnable tasks;
  • match task requirements to specialist role;
  • enforce dependencies;
  • enforce WorkPlan budgets;
  • enforce max concurrency;
  • claim tasks atomically;
  • maintain leases;
  • recover expired tasks;
  • invoke task workers;
  • schedule retries;
  • respect cancellation/pause;
  • avoid duplicate execution.

The scheduler SHALL NOT rely on LLM reasoning for atomic ownership.


14. Task Claims and Leases

Tasks MUST use claim/lease semantics.

Example:

status: CLAIMED
claimed_by: php-specialist/run-842
lease_until: 2026-09-09T08:42:00+02:00

Workers SHALL periodically heartbeat long-running tasks.

If a lease expires:

CLAIMED/RUNNING
      ↓
lease expires
      ↓
recovery process
      ↓
READY or FAILED

depending on retry policy.

Task ownership SHALL be assigned to a worker instance, not permanently to an agent identity.


15. Role-Based Scheduling

Tasks SHALL request roles/capabilities rather than concrete agents.

Correct:

required_role: php-specialist

Incorrect:

assigned_agent: php-agent-instance-3

This ensures future horizontal scaling.

Possible roles:

manager
operator
linux-specialist
web-specialist
php-specialist
database-specialist
wordpress-specialist
woocommerce-specialist
performance-specialist
security-specialist
lifecycle-specialist
backup-specialist
reviewer

16. Task Creation by Agents

Specialists MUST NOT have unrestricted authority to recursively generate arbitrary work.

A specialist may request a follow-up task via:

request_followup_task(...)

This request MUST pass through the Work Planner / Scheduler policy.

The runtime SHALL enforce limits such as:

max_children_per_task: 5
max_dependency_depth: 5
max_total_tasks: 200

Defaults MUST be configurable.

The planner SHALL detect obvious duplicates before task creation.


17. Work Budgets

Every WorkPlan MUST support resource budgets.

Minimum budget fields:

max_tasks:
max_parallel_tasks:
max_attempts_per_task:
max_model_calls:
max_tool_calls:
max_runtime_seconds:

Future:

max_cost_usd:
max_tokens:

Budget exhaustion MUST produce an explicit state/event.

The runtime MUST NOT silently continue unlimited autonomous execution.


18. Task Attempts

Each execution attempt SHALL create a separate record.

Table:

task_attempts

Fields:

id
tenant_id
task_id

worker_id

attempt_number

status

started_at
finished_at

error_code
error_summary

model_calls
tool_calls

trace_id

Task history MUST remain available after retries.


19. Durable Runtime Recovery

At startup, WPDoctor SHALL perform recovery.

Recovery steps:

open SQLite
   ↓
run migrations
   ↓
validate DB
   ↓
find expired task leases
   ↓
recover eligible tasks
   ↓
restore pending WorkPlans
   ↓
restore WAITING_APPROVAL items
   ↓
start scheduler

A container restart MUST NOT lose the operational state of existing work.


20. Operational Persistence Schema

Initial SQLite SHOULD contain at minimum:

schema_migrations

tenants

hosts
sites
capabilities

incidents
evidence

workplans
tasks
task_dependencies
task_attempts

approvals

activity_events

audit_events

artifacts
memory_references

Additional tables MAY be added through migrations.


21. Database Migration System

Schema migrations SHALL exist from the first implementation.

Do not use ad-hoc:

CREATE TABLE IF NOT EXISTS ...

as the permanent migration strategy.

Choose a versioned migration mechanism.

Every release changing schema MUST provide forward migration.


22. Semantic Activity Feed

WPDoctor SHALL implement a human-readable semantic activity stream.

This is a distinct architectural plane.

It MUST NOT be treated as ordinary stdout logging.

The purpose is to answer:

What is the agent doing?

What has it learned?

What changed?

What will it do next?

Why is it waiting?

The activity feed SHALL summarize operational state without exposing hidden chain-of-thought.


23. No Chain-of-Thought Requirement

WPDoctor MUST NOT attempt to persist or display private model chain-of-thought.

Do NOT instruct models:

"Print everything you are thinking."

Instead, agents SHALL emit explicit concise operational summaries.

Allowed:

"The PHP-FPM pool is saturated and nginx errors correlate with max_children exhaustion."

Not required:

internal hidden reasoning token stream

Activity is a product-facing operational narrative.


24. ActivityEvent Domain Model

Every semantic event SHALL have a structured model.

Required fields:

id:
tenant_id:

incident_id: optional
workplan_id: optional
task_id: optional

actor:
  type:
  role:
  worker_id: optional

event_type:

severity:

title:
message:

target:
  host_id: optional
  site_id: optional
  service: optional

evidence_refs: []
artifact_refs: []

created_at:

25. Canonical Activity Event Types

Initial event vocabulary:

WORKPLAN_CREATED
WORKPLAN_STARTED
WORKPLAN_COMPLETED
WORKPLAN_FAILED

TASK_CREATED
TASK_READY
TASK_CLAIMED
TASK_STARTED
TASK_BLOCKED
TASK_RETRYING
TASK_COMPLETED
TASK_FAILED
TASK_CANCELLED

INVESTIGATION_STARTED

FINDING
HYPOTHESIS_CREATED
HYPOTHESIS_UPDATED
DIAGNOSIS

PLAN_CREATED
PLAN_UPDATED

ACTION_PROPOSED
ACTION_STARTED
ACTION_COMPLETED
ACTION_FAILED

VALIDATION_STARTED
VALIDATION_PASSED
VALIDATION_FAILED

APPROVAL_REQUIRED
APPROVAL_GRANTED
APPROVAL_DENIED

HANDOFF_REQUESTED
FOLLOWUP_TASK_CREATED

MEMORY_RECALLED
LEARNING_CANDIDATE_CREATED

BUDGET_WARNING
BUDGET_EXHAUSTED

Do not proliferate event types unnecessarily.

New event types require review.


26. Human Narrative Requirements

Activity messages MUST be:

  • concise;
  • factual;
  • operational;
  • understandable by a sysadmin;
  • specific about target;
  • explicit when evidence is incomplete;
  • explicit when a hypothesis changes.

Example:

TASK-203 · PHP Specialist

PHP-FPM has reached pm.max_children 17 times during the last 15 minutes.
I will now correlate those events with nginx 502 timestamps before proposing a remediation.

Example after failed verification:

TASK-203 · Operator

The initial hypothesis does not fully explain the incident: 502 responses continue after PHP worker pressure returned to normal.
I will inspect database latency during the same time window.

Example plan change:

TASK-203 · Operator

The evidence now points to long-running WooCommerce queries as the primary cause.
PHP-FPM saturation appears to be secondary.
Next I will validate the affected query pattern before proposing an index change.

This is the desired level of narration.


27. Activity Emission Rules

A task MUST NOT remain operationally silent during meaningful state changes.

Emit semantic activity when:

  • task starts;
  • investigation direction changes;
  • relevant evidence is found;
  • a hypothesis is created or invalidated;
  • diagnosis materially changes;
  • a remediation plan is produced;
  • an action begins;
  • action fails;
  • validation passes/fails;
  • human approval is required;
  • task becomes blocked;
  • retry occurs;
  • task completes.

Do NOT emit events for every low-level command.

Semantic Activity MUST remain signal-rich.


28. Task Current Summary

In addition to immutable activity history, every Task SHALL expose mutable operational summary fields:

current_summary:
next_action:

Example:

current_summary: >
  PHP-FPM saturation is confirmed, but current evidence suggests
  it is secondary to long-running WooCommerce database queries.

next_action: >
  Correlate slow query timestamps with nginx upstream failures.

These fields SHALL be shown directly on the Kanban card/detail UI.


29. Activity vs Audit vs Telemetry

These systems MUST remain distinct.

Activity

Answers:

What is the agent doing?
What has it discovered?
What is next?

Human-oriented.


Audit

Answers:

What action actually happened?
Who caused it?
What target was affected?
Was it approved?
What was the result?

Security/compliance-oriented.


Telemetry

Answers:

How long did it take?
Which model/tool failed?
How many calls occurred?
What is the trace?

Engineering-oriented.


Hindsight

Answers:

What durable knowledge has the agent learned about this tenant?

Memory-oriented.


The separation is:

Plane Primary purpose
TaskBoard What work remains?
Activity What is happening now?
Audit What actions actually occurred?
Telemetry How is the runtime behaving technically?
Hindsight What durable knowledge was learned?

No plane SHALL be overloaded to replace another.


30. Evidence

Activity events may reference technical evidence.

Example:

event_type: FINDING

message: >
  PHP-FPM reached max_children repeatedly.

evidence_refs:
  - evid-1001
  - evid-1002

The WebUI SHALL allow a human to drill down from semantic summary into underlying evidence.

Evidence SHOULD contain:

source
timestamp
target
observation
raw artifact reference
confidence

31. Raw Logs and Artifacts

Large technical output SHALL NOT be stored inline in semantic activity messages.

SQLite SHALL only contain metadata/reference.

Initial artifact path:

/data/artifacts/

Recommended layout:

/data/artifacts/
└── incidents/
    └── INC-104/
        └── TASK-203/
            ├── nginx-errors.log
            ├── php-fpm.log
            ├── slow-query.log
            └── report.json

Artifact table fields:

id
tenant_id
incident_id
task_id

type
path
mime_type

size
checksum

created_at

Future artifact storage MAY be moved to S3/SeaweedFS without changing domain references.


32. Agent Logging Requirements

Every agent/role SHALL produce two distinct forms of logging:

Structured technical logs

For engineering:

timestamp
level
tenant
workplan
task
agent role
trace
message

Semantic Activity

For humans.

Example technical log:

INFO task_worker tool=ssh_exec duration_ms=231 exit_code=0

Corresponding semantic event:

PHP-FPM status was successfully inspected. All configured workers are currently occupied.

Both are useful.

Neither replaces the other.


33. Operator Identity

The primary orchestrating role SHOULD be represented in the WebUI as:

Operator

Internal role:

wpdoctor-manager / operator

Example human narrative:

Operator · TASK-203

I am starting an investigation into intermittent 502 errors on shop.example.com.

Specialists may be shown as:

Linux
Web
PHP
Database
WordPress
WooCommerce
Performance
Security
Reviewer

The UI does not need to expose ADK framework internals.


34. Runtime WebUI

WPDoctor SHALL include an operator WebUI from early development.

It is not a future SaaS customer portal.

It is an operational UI for developers/operators to observe and control the tenant runtime.

Initial technology recommendation:

FastAPI
+
small frontend
+
SQLite
+
Server-Sent Events

Exact frontend framework is implementation-level unless it creates architectural coupling.

Avoid unnecessary complexity.


35. Required WebUI Sections

Minimum navigation:

Overview
Incidents
Tasks
Activity
Servers
Sites
Audit

Recommended subsequent sections:

Approvals
Memory
Policies
Artifacts

36. Kanban View

The Tasks page SHALL provide a Kanban-style board.

Initial columns:

BACKLOG
READY
RUNNING
REVIEW
WAITING
BLOCKED
DONE
FAILED

UI MAY merge some internal states visually.

Example card:

TASK-203

Investigate 502
shop.example.com

PHP Specialist

RUNNING · 8m

PHP-FPM saturation confirmed.
Checking DB latency correlation.

Next:
Inspect slow queries

Incident INC-104
Risk R0

Cards SHALL prioritize human understanding over displaying raw internal metadata.


37. Task Detail View

Task detail MUST show:

Task ID
Title
Objective
Status
Target
Assigned role
Worker
Risk
Dependencies
Attempts
Current summary
Next action

and tabs/sections:

Activity
Findings
Evidence
Tool Calls
Attempts
Approvals
Artifacts
Raw Logs

38. Incident View

Incident detail SHOULD aggregate related Task activity into one chronological narrative.

Example:

07:31 Operator
Started investigation.

07:32 PHP Specialist
Detected repeated PHP-FPM worker exhaustion.

07:35 Operator
Initial hypothesis incomplete; expanding investigation to database.

07:38 Database Specialist
Detected long-running WooCommerce queries.

07:40 Operator
Primary cause identified as database query latency.

07:41 Operator
Prepared remediation plan and requested approval.

This should allow an operator to understand the incident without opening every task.


39. Live Activity View

WebUI SHALL provide a live semantic event stream.

Example:

07:31 TASK-203 started by Operator
07:32 PHP found FPM saturation
07:33 TASK-211 claimed by Linux
07:34 TASK-199 completed
07:35 TASK-203 hypothesis updated
07:36 TASK-212 waiting for approval

This view is intended as:

semantic tail -f of WPDoctor

40. Real-Time Transport

Initial WebUI real-time updates SHOULD use Server-Sent Events.

Endpoint example:

GET /api/v1/events/stream

SSE is preferred initially because communication is predominantly:

runtime → browser

User actions SHALL use regular HTTP.

Examples:

POST /tasks/{id}/retry
POST /tasks/{id}/cancel
POST /workplans/{id}/pause
POST /approvals/{id}/approve
POST /approvals/{id}/deny

WebSockets MAY be introduced later if genuinely necessary.


41. Web API

The runtime SHALL expose a typed internal REST API.

Suggested namespace:

/api/v1/

Minimum endpoints:

GET  /health

GET  /overview

GET  /incidents
GET  /incidents/{id}

GET  /workplans
GET  /workplans/{id}

GET  /tasks
GET  /tasks/{id}

GET  /activity
GET  /events/stream

GET  /hosts
GET  /hosts/{id}

GET  /sites
GET  /sites/{id}

GET  /audit

GET  /approvals
POST /approvals/{id}/approve
POST /approvals/{id}/deny

POST /tasks/{id}/retry
POST /tasks/{id}/cancel

POST /workplans/{id}/pause
POST /workplans/{id}/resume
POST /workplans/{id}/cancel

Mutation endpoints MUST invoke domain services and policy.

HTTP handlers MUST NOT mutate SQLite state directly.


42. Approvals

Human approvals SHALL integrate with TaskBoard.

A task requiring approval transitions:

RUNNING
   ↓
WAITING_APPROVAL

Approval record SHALL contain:

id
tenant_id
incident_id
workplan_id
task_id

operation
risk

requested_by
requested_at

summary
proposed_action
rollback_plan

status

decided_by
decided_at
decision_comment

The WebUI MUST make pending approvals highly visible.


43. Memory Integration

Hindsight remains separate from TaskBoard.

Do NOT store operational queue state in Hindsight.

Correct responsibility split:

SQLite
    =
what exists and what is happening

Hindsight
    =
what was learned and remains useful

At task/incident completion:

Evidence + Outcome
        ↓
LEARN
        ↓
Memory candidate
        ↓
validation / curation
        ↓
Hindsight

SQLite MAY store:

memory_references

to link incidents/tasks to Hindsight entries.


44. Memory Narration

When memory materially influences a task, Activity MAY show:

Historical context recalled:

srv01 has previously experienced IO contention during nightly backups.
I will verify whether the current incident matches that pattern.

Do not expose irrelevant memory recall noise.


45. Runtime Container Layout

Initial container:

WPDoctor tenant runtime
│
├── ADK runtime
├── Manager
├── Specialists
├── Work Planner
├── Task Scheduler
├── Operations Engine
├── Policy Engine
├── Web API
├── WebUI
├── SQLite
│   └── /data/wpdoctor.db
│
├── artifact workspace
│   └── /data/artifacts/
│
└── external clients
    ├── Hindsight
    ├── Infisical
    └── customer SSH hosts

The UI/API may run in the same process initially or as cooperating processes within the same deployment.

Avoid splitting into microservices in v1.


46. Kubernetes Runtime Model

Initial Kubernetes recommendation:

StatefulSet or Deployment
replicas: 1

PVC
accessMode:
  ReadWriteOnce

mount:
  /data

One active pod per tenant.

Do NOT attempt active-active SQLite.

If orchestration requires multiple simultaneously writable WPDoctor pods, migrate persistence before scaling.


47. Database Migration Trigger to PostgreSQL

SQLite remains valid while all are true:

single active runtime per tenant
single writable node
moderate task concurrency
local persistent filesystem
no distributed scheduler

PostgreSQL migration SHOULD occur when one or more becomes necessary:

multiple active WPDoctor pods per tenant
distributed task workers
active-active HA
central fleet scheduler
large cross-tenant control plane
high concurrent write throughput
complex fleet-wide analytics

Do NOT migrate merely because PostgreSQL is theoretically more scalable.


48. PostgreSQL Compatibility Requirement

All domain repositories MUST avoid exposing SQLite-specific semantics to callers.

Example:

TaskRepository.claim()

may internally use:

SQLite:
BEGIN IMMEDIATE

PostgreSQL:
SELECT ... FOR UPDATE SKIP LOCKED

The caller sees the same behavior.


49. Security Requirements

The WebUI introduces additional security boundaries.

Minimum:

  • listen only on configured interface;
  • authentication required in non-development mode;
  • no raw secrets displayed;
  • redact SSH credentials;
  • redact DB credentials;
  • redact environment secrets;
  • CSRF protection where relevant;
  • authorization required for approval/mutation endpoints;
  • audit all operator mutations.

For development, local-only authentication bypass MAY be configurable.

It MUST NOT be the production default.


50. Semantic Log Security

Activity messages MUST NOT include:

passwords
tokens
private keys
database credentials
session cookies
secret environment values

Evidence and raw logs must pass redaction where practical.

Remote content remains untrusted.

A malicious WordPress plugin or log line MUST NOT be able to generate trusted Activity instructions.


51. Event Origin

Activity events SHALL only be generated through trusted WPDoctor code paths.

Remote systems may provide evidence used to construct an Activity event, but raw remote text MUST NOT be able to directly publish privileged event semantics.


52. Audit Immutability Semantics

Activity events may be explanatory.

Audit events represent actual security-relevant facts.

Audit records SHOULD be append-only through application semantics.

Example:

ACTION_EXECUTED
operation=restart_php_fpm
target=srv01
approved_by=operator-x
result=success

Do not retroactively rewrite audit events.


53. OpenTelemetry

WPDoctor SHALL instrument:

workplan lifecycle
task lifecycle
agent invocation
specialist delegation
operation
tool call
SSH command
memory recall
memory retain
policy decision
approval wait
activity event generation

Trace IDs SHOULD be persisted on TaskAttempt and Audit records when available.

This permits navigation:

Human Activity
    ↓
Task
    ↓
Attempt
    ↓
Trace
    ↓
Tool / SSH details

54. Failure Handling

Every failure MUST be represented in three appropriate layers.

Example SSH timeout:

Activity

The host did not respond before the SSH timeout.
I will retry once before marking the task blocked.

Audit

Only if an operational action actually occurred.

Technical log

ssh_timeout host=srv01 timeout=15s

Task state

RETRYING

or:

BLOCKED

No silent retry loops.


55. Retry Policy

Tasks SHALL define retry semantics.

Example fields:

max_attempts
retryable_error_codes
backoff

Retries MUST generate Activity events.

Example:

TASK-203 · Retry 2/3

The previous SSH attempt timed out.
A second attempt will be made after 10 seconds.

56. Long-Running Task Heartbeats

Long tasks SHALL heartbeat.

Heartbeat SHOULD update:

lease_until
updated_at

Do not generate semantic Activity solely for heartbeat noise.

Activity is for meaningful progress.


57. Progress Model

Task progress MAY expose:

progress:
  completed_units:
  total_units:
  percent:

Only use percentages when meaningful.

Do not fabricate arbitrary percentages for open-ended investigations.

For investigations prefer:

current_summary
next_action

58. Human Intervention

Operators SHALL be able to:

approve
deny
retry
cancel
pause WorkPlan
resume WorkPlan

Future:

reprioritize
reassign role
add operator note
inject new evidence

Manual intervention SHALL create Activity and Audit records where relevant.


59. Cancellation

Cancellation semantics MUST be explicit.

Cancelling a WorkPlan:

  • prevents new tasks from being scheduled;
  • requests cancellation of interruptible running tasks;
  • does not assume currently executing remote shell commands can always be safely aborted;
  • records final state.

Cancellation does NOT imply rollback.

Rollback is separate.


60. Repository Structure Amendment

ADR-0017 repository tree SHALL be expanded with:

src/wpdoctor/
│
├── persistence/
│   ├── database.py
│   ├── migrations/
│   └── repositories/
│       ├── tenants.py
│       ├── inventory.py
│       ├── incidents.py
│       ├── workplans.py
│       ├── tasks.py
│       ├── approvals.py
│       ├── activity.py
│       ├── audit.py
│       └── artifacts.py
│
├── work/
│   ├── planner.py
│   ├── scheduler.py
│   ├── worker.py
│   ├── leases.py
│   ├── budgets.py
│   └── recovery.py
│
├── activity/
│   ├── service.py
│   ├── models.py
│   └── event_types.py
│
├── web/
│   ├── api/
│   ├── sse.py
│   └── ui/
│
└── ...

Exact filenames may differ slightly.

Architectural boundaries MUST remain equivalent.


61. Recommended New Domain Models

Add:

WorkPlan
Task
TaskDependency
TaskAttempt
ActivityEvent
Artifact

Existing:

Incident
Evidence
Approval
AuditEvent

shall integrate through IDs, not deeply nested serialized blobs.


62. Implementation Milestone Amendment

ADR-0017 rollout SHALL be revised.

M0 — Core contracts/runtime

domain models
repository interfaces
SQLite bootstrap
migration system
ADK runtime
Docker
tests

M1 — SSH / discovery / inventory

As ADR-0017.


M2 — Durable Work Orchestration

NEW mandatory milestone.

Implement:

WorkPlan
Task
TaskDependency
TaskAttempt
TaskBoard
Scheduler
claim/lease
heartbeat
retry
recovery
budgets

Implement WebUI skeleton.


M3 — Semantic Activity + WebUI

Implement:

ActivityEvent
ActivityService
current_summary
next_action

REST API
SSE
Kanban
Task detail
Incident activity
Live activity feed

M4 — Read-only SRE vertical slice

Implement first full diagnostic workflows.


M5 — Policy / approvals / controlled mutations

As previously defined.


M6 — WordPress performance/lifecycle

As previously defined.


M7 — Hindsight / LEARN / curator

As previously defined.


M8 — Dogfooding / eval corpus

As previously defined.


63. First Vertical Slice Amendment

The first 502/PHP-FPM vertical slice SHALL now prove ALL of:

incident creation
   ↓
WorkPlan creation
   ↓
Task decomposition
   ↓
task scheduling
   ↓
specialist claim
   ↓
semantic Activity
   ↓
SSH evidence collection
   ↓
diagnosis
   ↓
TaskBoard update
   ↓
policy
   ↓
approval if mutation
   ↓
execution
   ↓
validation
   ↓
audit
   ↓
task completion
   ↓
WorkPlan completion
   ↓
LEARN later

The developer MUST NOT bypass TaskBoard for convenience when testing this vertical slice.


64. Example End-to-End Narrative

Target desired behavior:

07:31 Operator
INC-104 created.
Intermittent 502 errors on shop.example.com will be investigated.

07:31 Operator
WorkPlan WP-22 created with 4 initial tasks.

07:32 PHP Specialist
TASK-203 started.
I will inspect PHP-FPM state and recent errors.

07:33 PHP Specialist
PHP-FPM reached pm.max_children 17 times during the last 15 minutes.

07:34 Operator
The current evidence suggests worker exhaustion, but I will correlate nginx failures before confirming it as the primary cause.

07:35 Web Specialist
nginx upstream failures match the PHP-FPM saturation windows.

07:36 Operator
The diagnosis currently points to PHP-FPM worker exhaustion.
A database check has been scheduled to determine whether workers are blocked by slow queries.

07:38 Database Specialist
Long-running WooCommerce queries coincide with worker exhaustion.

07:39 Operator
Diagnosis updated.
Slow WooCommerce database queries are the primary cause; PHP-FPM saturation is secondary.

07:40 Operator
A remediation plan has been prepared and requires approval.

07:44 Human Operator
Approved.

07:44 Database Specialist
Remediation started.

07:45 Database Specialist
Database change completed successfully.

07:46 Operator
Validation is running.

07:47 Operator
Validation passed.
No further nginx 502 responses were observed and PHP-FPM worker occupancy returned to normal.

07:47 Operator
TASK-203 completed.
INC-104 resolved.

This is the minimum quality target for semantic observability.


65. Definition of Done for TaskBoard

TaskBoard is NOT complete until:

[ ] tasks persist across restart
[ ] dependencies work
[ ] atomic claims work
[ ] leases work
[ ] expired task recovery works
[ ] retries work
[ ] budgets work
[ ] cancellation works
[ ] task attempts are preserved
[ ] multiple specialists can process tasks concurrently
[ ] no duplicate execution occurs in normal runtime operation

66. Definition of Done for Activity Feed

Activity is NOT complete until:

[ ] events are persisted
[ ] events are structured
[ ] events reference tasks/incidents
[ ] events can reference evidence
[ ] current_summary exists
[ ] next_action exists
[ ] agents emit meaningful milestones
[ ] failed hypotheses can be narrated
[ ] retries are narrated
[ ] approvals are narrated
[ ] task completion is narrated
[ ] secret leakage tests exist

67. Definition of Done for WebUI

WebUI MVP is NOT complete until an operator can:

[ ] view incidents
[ ] view TaskBoard
[ ] inspect one Task
[ ] see current_summary
[ ] see next_action
[ ] follow live Activity
[ ] view evidence
[ ] view task attempts
[ ] view raw artifacts/logs
[ ] inspect audit records
[ ] approve/deny pending operation
[ ] retry failed task
[ ] cancel task
[ ] pause/cancel WorkPlan

68. Tests Required

New mandatory tests:

Persistence

restart recovery
migration
foreign key integrity
WAL behavior

Scheduler

claim race
expired lease
retry
dependency blocking
budget exhaustion
task cancellation

Activity

event persistence
event ordering
secret redaction
task summary updates

Web API

read endpoints
approval authorization
mutation audit
SSE stream

Full integration

runtime killed while work active
runtime restarted
task recovered
execution continues

69. Anti-Patterns Explicitly Forbidden

Do not implement:

ADK Session = source of truth

stdout logs = TaskBoard

Hindsight = task queue

LLM prompt = workflow persistence

one giant JSON incident blob

specialists writing SQLite directly

unbounded recursive task generation

long-running DB transactions

active-active SQLite

generic shell output copied wholesale to Activity

chain-of-thought exposed as observability

silent autonomous operations

semantic narration generated only after incident ends

70. Product-Level Consequence

These additions intentionally move WPDoctor from:

multi-agent chatbot with SSH

toward:

durable WordPress SRE operating runtime

The runtime now contains explicit primitives for:

work
coordination
state
recovery
human understanding
control
memory
audit

This is a deliberate architectural direction.


71. Relationship with ADK

ADK SHALL remain responsible for:

agent orchestration
delegation
LLM interaction
specialist reasoning

WPDoctor itself SHALL own:

WorkPlans
Tasks
Scheduler
durability
policy
inventory
incidents
activity
audit
memory semantics

This prevents WPDoctor business state from becoming coupled to ADK internals.

If ADK changes in the future, operational state remains portable.


72. Architectural Principle

The primary principle introduced by this ADR is:

Autonomous work that matters must be durable, inspectable, resumable and understandable by a human operator.

A second principle is:

No long-running WPDoctor task should become a black box.

At any point an operator should be able to determine:

what the system is trying to achieve
what tasks exist
what is running
who is working on it
what has been discovered
what hypothesis currently exists
what will happen next
what is blocked
what requires approval
what actions were actually executed

73. Instructions to Implementing Architect / Agent

Before implementation:

  1. Read ADR-0017.
  2. Read this ADR completely.
  3. Treat this ADR as an amendment to the orchestration, persistence and observability sections of ADR-0017.
  4. Do not remove provider-agnostic requirements.
  5. Do not introduce Wetopi-specific assumptions.
  6. Preserve repository boundaries.
  7. Implement SQLite abstraction from day one.
  8. Implement migrations from day one.
  9. Implement TaskBoard before broad multi-agent operations.
  10. Implement Activity as a first-class domain object, not formatted stdout.
  11. Build the WebUI against the same canonical repositories/API used by runtime services.
  12. Do not make the WebUI a second source of truth.
  13. Do not use Hindsight for workflow state.
  14. Do not expose private chain-of-thought.
  15. Record any required architectural deviation in a new ADR.

74. First Expected Delivery

The first delivery after adopting ADR-0002 SHOULD demonstrate:

start WPDoctor container
   ↓
SQLite initialized + migrations
   ↓
create WorkPlan
   ↓
create dependent Tasks
   ↓
scheduler claims task
   ↓
specialist runs
   ↓
Activity events appear live
   ↓
task detail updates
   ↓
runtime killed
   ↓
runtime restarted
   ↓
expired work recovered
   ↓
Task resumes/retries
   ↓
WebUI shows complete history

A minimal fake/test operation MAY be used before SSH integration for this demonstration.


75. Acceptance Criteria

ADR-0002 is considered implemented when:

  1. /data/wpdoctor.db is the durable operational store.
  2. SQLite runs in WAL mode.
  3. Repository abstractions isolate persistence.
  4. schema migrations exist.
  5. WorkPlans are persistent.
  6. Tasks are persistent.
  7. Task dependencies work.
  8. Task attempts are retained.
  9. scheduler uses leases.
  10. expired work is recoverable.
  11. runtime restart does not lose active plans.
  12. budgets prevent unbounded work.
  13. specialists cannot create unlimited recursive tasks.
  14. ActivityEvents are persistent and structured.
  15. Tasks expose current_summary.
  16. Tasks expose next_action.
  17. semantic events are shown live.
  18. raw technical logs remain separate.
  19. Audit remains separate.
  20. Hindsight remains separate.
  21. WebUI shows Kanban.
  22. WebUI shows Task detail.
  23. WebUI shows Incident narrative.
  24. WebUI supports live SSE.
  25. WebUI supports approvals.
  26. WebUI supports retry/cancel/pause actions.
  27. secrets are redacted from Activity.
  28. no private chain-of-thought is required or displayed.
  29. OpenTelemetry can correlate TaskAttempt to trace.
  30. first SRE vertical slice uses the durable orchestration path.

76. Final Decision

Adopt this ADR before implementing complex WPDoctor multi-agent workflows.

ADR-0017 remains authoritative for:

provider agnosticism
SSH boundary
specialist model
Operations / Skills / Tools
Policy
Hindsight
tenant model
security
WordPress SRE scope

ADR-0002 becomes authoritative for:

runtime persistence
SQLite
WorkPlans
TaskBoard
Scheduler
leases
retries
budgets
durability
semantic Activity
agent narration
WebUI
SSE
operator controls
runtime recovery
SQLite → PostgreSQL evolution

The resulting WPDoctor v1 architecture SHALL be treated as:

A durable, observable, provider-agnostic WordPress SRE runtime, not merely an ADK multi-agent application.

Correspondencia: este documento es el ADR-0018 del Knowledge Plane y corresponde al ADR-0002 del repositorio de producto.