Skip to the content.

Task 106 — DelegatedTask persistence (SQLite)

Phase: 8 Status: done Owner: — Slug: delegated-task-persistence Studio Stage: 8 Completed: 2026-08-17

Goal

Заменить in-memory ConcurrentDictionary в TaskLifecycleProtocol на SQLite persistence. DelegatedTask должен переживать restart агента.

Acceptance criteria

Dependencies

Sub-tasks

Implementation notes

Validation

Follow-ups (next roadmap tick)

  1. Surface a small IDelegatedTaskStoreAdmin.ListAllAsync() for ops dashboards (volume, age, stuck count).
  2. Add index on expires_at to make the prune query O(log n) when the table grows.
  3. Add parent_task_id column (task_107 will need it for sub-process / parallel-gateway fan-out).

Completion note (2026-08-17)

Replaced the in-memory ConcurrentDictionary<string, DelegatedTask> in TaskLifecycleProtocol with a write-through SQLite store (IDelegatedTaskStore + SqliteDelegatedTaskStore). The protocol still keeps an in-memory cache for fast reads, but the cache is now hydrated from ListPendingAsync() on construction (Accepted/Working/AwaitingInput) and every state transition is persisted. A background Timer (5 min, configurable) scans for tasks past their ExpiresAt, transitions them to Expired, and prunes terminal rows older than 1 h. The 2-arg constructor (TaskLifecycleProtocol(localAgentId, logger)) is preserved for the existing Phase-3 tests so all 30 pre-existing tests stay green unchanged.

Validation:

Files changed:

Unblocks: task_107 (parent/child relationships), task_108 (checkpoint persistence — same pattern), and the workflow executor in task_104/105 that needs durable task state across restarts.

Scope / Likely files