Appearance
Task Deletion Workflow β
This document describes the workflow for handling task deletion events between the API and Brain, including project plan cleanup and event propagation.
Overview β
When a user deletes a task, the system must ensure that:
- The task is removed from the database
- The associated feature is removed from project plan files
- Other system components are notified of the deletion
- The process is idempotent and handles failures gracefully
Architecture β
βββββββββββββββ DELETE /api/tasks/:id βββββββββββββββ
β Client β ββββββββββββββββββββββββββββΆ β API Server β
βββββββββββββββ ββββββββ¬βββββββ
β
βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Remove from β β Delete from β β Queue Brain β
β plan.md β β Database β β Message β
ββββββββββ¬βββββββββ βββββββββββββββββββ ββββββββββ¬βββββββββ
β β
β βΌ
β βββββββββββββββββββ
β β Brain Message β
β β Queue β
β ββββββββββ¬βββββββββ
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββ
β β
βΌ βΌ
βββββββββββββββββββ
β Brain Handler β
β (task_deleted) β
ββββββββββ¬βββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Verify/Cleanupβ β Log Activity β β Publish Event β
β plan.md β β β β β
βββββββββββββββ βββββββββββββββββββ βββββββββββββββββββEvent Schema β
task_deleted Message β
When a task is deleted, the API sends a message to the Brain with the following payload:
typescript
interface TaskDeletedPayload {
/** The ID of the deleted task */
taskId: string;
/** Reference to the project/plan file (source_ref) */
projectId: string;
/** The unique identifier of the feature in plan.md (plan_line_uid) */
featureId: string;
/** Who initiated the deletion ("user", "api", etc.) */
deletedBy: string;
/** ISO timestamp of when the deletion occurred */
timestamp: string;
}Example payload:
json
{
"taskId": "task-abc123",
"projectId": "/path/to/.project/plan.md:42",
"featureId": "octopai:feature123",
"deletedBy": "user",
"timestamp": "2026-03-29T15:09:28.533Z"
}API Flow β
1. Task Deletion Endpoint β
The DELETE /api/tasks/:id endpoint handles task deletion:
- Lookup Task: Fetches the task to get its
plan_line_uidandsource_ref - Remove from Plan: If the task has a
plan_line_uid, callsremoveTaskLineFromPlan()to remove the feature from the plan file - Delete from Database: Removes the task record from SQLite
- Queue Brain Message: Creates a
task_deletedmessage and queues it for the Brain - Broadcast Event: Emits a WebSocket event for real-time UI updates
typescript
// src/api/routes/tasks.ts
app.delete("/:id", async (c) => {
// 1. Get task details
const taskRow = db.query("SELECT ...").get(id);
// 2. Remove from plan.md if applicable
if (taskRow.plan_line_uid && taskRow.source_ref) {
const removedFromPlan = await removeTaskLineFromPlan(
planFilePath,
taskRow.plan_line_uid
);
}
// 3. Delete from database
db.run("DELETE FROM tasks WHERE id = ?", [id]);
// 4. Queue message for Brain
queueMessage(db, {
type: "task_deleted",
payload: { taskId: id, projectId, featureId, deletedBy, timestamp }
});
// 5. Broadcast event
broadcast("tasks", "task.deleted", { taskId: id, removedFromPlan });
});Brain Flow β
1. Message Reception β
The Brain receives task_deleted messages through the standard message handling pipeline:
typescript
// src/brain/brain.ts
private async handleArmMessage(message: QueueMessage): Promise<void> {
switch (message.type) {
case "task_deleted": {
const payload = message.payload as TaskDeletedPayload;
await this.handleTaskDeletion(payload);
break;
}
// ... other cases
}
}2. Deletion Handler β
The Brain's deletion handler performs three main operations:
a. Idempotent Plan Cleanup β
Even though the API attempts to remove the feature from plan files, the Brain verifies this and performs cleanup if needed:
typescript
private async verifyAndCleanupPlanFeature(
projectId: string,
featureId: string
): Promise<boolean> {
// Parse projectId to get file path
// (handles both "path:line" format and direct paths)
// Attempt to remove the line by UID
const removed = await removeTaskLineFromPlan(planFilePath, featureId);
return removed; // true if cleanup was performed, false if already absent
}This is idempotent: calling it multiple times for the same deleted task is safe.
b. Activity Logging β
The handler logs the deletion for observability:
typescript
this.logActivity("brain", "task_deleted", taskId, {
projectId,
featureId,
deletedBy,
timestamp,
planCleanupNeeded: cleanupPerformed,
});c. Event Publication β
The deletion is published as a system event for other consumers:
typescript
await this.publishEventViaApi({
subject: `coleo.events.task.${taskId}.deleted`,
type: "task.deleted",
data: { taskId, projectId, featureId, deletedBy, timestamp, planCleaned }
});3. Error Handling β
The handler is designed to be resilient:
- Plan file not found: Logs warning, continues
- Feature already absent: Returns successfully (idempotent)
- Event publishing fails: Logs error, does not fail the operation
- Any other error: Caught and logged, operation continues
typescript
private async handleTaskDeletion(payload: TaskDeletedPayload): Promise<void> {
try {
// ... perform cleanup, logging, event publishing
} catch (err) {
// Log error but don't throw - deletion notification should not fail
this.log(`Error processing task deletion: ${err}`);
this.logActivity("brain", "task_deletion_failed", taskId, { error: err });
}
}Plan File Format β
Tasks in plan files are marked with unique identifiers using HTML comments:
markdown
## Phase 1: Foundation
### Deliverables
- [ ] Implement user authentication <!--octopai:abcd1234-->
- [ ] Add database schema for users <!--octopai:efgh5678-->
- [x] Set up project structure <!--octopai:ijkl9012-->The removeTaskLineFromPlan() function:
- Reads the plan file
- Finds the line containing
<!--octopai:{featureId}--> - Removes that line
- Writes the updated content back
Testing β
Unit Tests β
Tests are located in src/brain/__tests__/task-deletion-handler.test.ts:
- Handler Tests: Verify message processing, activity logging, event publishing
- Cleanup Tests: Verify idempotent plan cleanup, file path parsing, error handling
- Integration Tests: Verify message routing through
handleArmMessage
Run tests:
bash
bun test src/brain/__tests__/task-deletion-handler.test.tsManual Testing β
- Create a task from a plan.md file
- Verify the task has a
plan_line_uidin the database - Delete the task via API
- Verify:
- Task removed from database
- Feature removed from plan.md
task_deletedmessage queued- Brain processes the message successfully
- Activity logged
- Event published
Related Code β
- API Route:
src/api/routes/tasks.ts- DELETE endpoint - Brain Handler:
src/brain/brain.ts-handleTaskDeletion(),verifyAndCleanupPlanFeature() - Plan Parser:
src/brain/plan-parser.ts-removeTaskLineFromPlan() - Message Types:
src/types/index.ts-MessageTypeunion,QueueMessage - Brain Inbox:
src/types/brain-inbox.ts- Payload validation
Future Enhancements β
- Reindexing: Trigger search reindexing when tasks are deleted (if search is implemented)
- Retry Logic: Add retry mechanism for failed plan cleanup attempts
- Batch Deletion: Optimize for bulk task deletion scenarios
- Undo Support: Consider adding soft-delete and restore capability
- Notifications: Notify assigned arms when their tasks are deleted
Last updated: 2026-03-29
