9.1 KiB
status, system, created, updated, owners
| status | system | created | updated | owners | |
|---|---|---|---|---|---|
| active | tasks | 2026-08-02 | 2026-08-09 |
|
Interrupted Task Indicator Requirements
Overview
This document is the migrated task-system source for the capability. The source detail below remains authoritative while the system is migrated into separate requirement and design records.
Requirements
REQ-TASKS-INTERRUPTED-TASK-INDICATOR-001: Interrupted Task Indicator
Intent: Preserve the observable task or workflow behavior recorded by the legacy specification.
Acceptance criteria
- AC-TASKS-INTERRUPTED-TASK-INDICATOR-001.1: When a consumer uses this capability, the system shall provide the observable behavior and exclusions documented below.
Migrated source detail
Why
When Kandev crashes, is killed, or restarts while tasks are mid-turn, those
sessions are interrupted: the agent process is gone and the turn was cut short.
Startup reconciliation already flips such sessions to WAITING_FOR_INPUT and
the task to REVIEW, so after a restart an interrupted task is visually
indistinguishable from a task that finished its turn and is waiting normally.
Operators cannot tell which tasks lost work to the crash. This spec adds a
durable "interrupted" marker set at startup for tasks whose sessions were
mid-turn, surfaced as a red icon in the task list.
What
- At startup, when reconciliation finds a session that was
STARTINGorRUNNING(mid-turn) when the backend died, the owning task is marked interrupted with a durable task metadata keyinterrupted_atholding the reconciliation timestamp (RFC 3339 UTC). - Sessions that were
WAITING_FOR_INPUT,IDLE,CREATED, or terminal at startup are not marked: they were not interrupted mid-work. - Archived or deleted tasks are not marked (they do not appear in the active task list).
- The task API exposes
interrupted: trueon the task DTO while the marker is present; it is derived from the metadata key, so no schema migration is required. - Task list surfaces render a red alert icon beside the task while
interruptedis true: sidebar task rows, the mobile task-switcher drawer (shared row rendering), kanban board cards, graph/swimlane nodes, the rich task-list row, and the open-task state icon. The icon carries an accessible label and tooltip ("Interrupted by restart"). - The marker clears when a session of the task next enters
STARTINGorRUNNING— work has resumed, so the task is no longer interrupted — and the cleared state is published over the existingtask.updatedevent so open clients drop the icon live. - The red icon renders instead of the idle/done affordances only. Pending
permission, pending clarification, generating/background activity, and
running spinners keep their existing precedence; terminal
COMPLETED,FAILED, andCANCELLEDstates keep their existing icons.
Data model
No schema change. The marker lives in the existing tasks.metadata JSON
column under a new reserved key:
MetaKeyInterruptedAt = "interrupted_at" // value: RFC 3339 UTC timestamp string
Task metadata is already serialized into the API task DTO and already
survives restarts. The repository's existing SetTaskMetadataKey /
RemoveTaskMetadataKey helpers (concurrent-key-safe JSON patch, both SQLite
and Postgres) are the only writers; nothing else may mutate the key.
API surface
v1.Taskgainsinterrupted bool json:"interrupted,omitempty".- The field is computed at DTO conversion time in both task serializers
(
internal/task/dtoandinternal/task/modelsToAPI) asmetadata["interrupted_at"] != nil. It is not a stored column. - The field flows through every existing task payload automatically: boot
payload,
kanban.update,task.created,task.updated,task.state_changed, andGET /api/v1/tasks/:id. - No new HTTP route, WebSocket action, or event type.
State machine
The marker follows this lifecycle:
unmarked: nointerrupted_atkey.marked:interrupted_atpresent; task DTO reportsinterrupted: true.cleared: key removed; DTO reportsinterrupted: false(omitted).
Transitions:
unmarked -> markedat startup reconciliation when a preservedexecutors_runningrow's session wasSTARTINGorRUNNINGand the task exists and is not archived. Overwriting an existing key is safe: a marked task cannot have a mid-turn session at the next startup unless it was resumed and crashed again.marked -> clearedwhen any session of the task transitions intoSTARTINGorRUNNING(launch, resume, prompt dispatch, agent-ready wake). The transition chokepoint in the orchestrator (updateTaskSessionStateWithHook/setSessionStarting; the implementer verifies the funnel covers every start path) removes the key and publishestask.updatedonly when the key was actually removed.- Terminal task/session transitions do not clear the marker; terminal state icons take precedence over the red icon, and archiving/deleting the task removes the row with its metadata.
Permissions
None. The marker is display metadata on a task the viewer can already see. It is user-writable only through the generic task metadata update surface and has no effect beyond the icon.
Failure modes
- A metadata write fails during reconciliation: the marker is skipped with a warning and startup continues; the task simply shows no icon until the next restart.
- A metadata removal fails during a session start: the marker survives and the next successful start transition clears it; the icon may briefly persist behind the running spinner, which takes precedence.
- Remote executors: the backend connection is severed even if the remote agent is still alive. The task is marked. If the remote status poll later reports the session running again and the session transitions, the marker clears; if not, the marker stays until the next resume. This is acceptable — from Kandev's perspective the turn was cut off.
- An already-open client during startup reconnects to the boot payload, which carries the marker; no startup-time event is required.
- A
task.updatedevent that omitsinterruptedmust not wipe a set marker in client state (frontend merge preserves the field when the payload omits it, mirroringforeground_activity).
Persistence guarantees
- The marker is durable in
tasks.metadataand survives any number of restarts until a session start clears it. - Clearing is a normal key removal; a crash between removal and the
task.updatedpublish leaves the client icon stale until the next payload, never a corrupt row.
Scenarios
- GIVEN a task whose primary session was
RUNNINGwhen the backend died, WHEN the backend starts and reconciliation runs, THEN the task's metadata containsinterrupted_at, the task DTO reportsinterrupted: true, and the sidebar row, board card, graph node, rich list row, and mobile switcher row show the red alert icon. - GIVEN that task also has a stored
generatingtask summary, WHEN reconciliation changes the primary session toWAITING_FOR_INPUT, THEN the summary clearsgeneratingand the red alert icon is not hidden by a stale running spinner. - GIVEN a task whose session was
WAITING_FOR_INPUTwhen the backend died, WHEN reconciliation runs, THEN the task is not marked and shows no red icon. - GIVEN an archived task with a mid-turn session row, WHEN reconciliation runs, THEN the task is not marked.
- GIVEN a marked task, WHEN the user resumes the session and it enters
STARTING/RUNNING, THEN the marker is removed,task.updatedis published, and every surface drops the red icon (running spinners take over). - GIVEN a marked task that is never resumed, WHEN the backend restarts again, THEN the marker survives and the icon still renders.
- GIVEN a marked task whose state is
COMPLETED, WHEN any surface renders it, THEN the green done icon wins and no red icon is shown. - GIVEN a
task.updatedevent without aninterruptedfield for a marked task, WHEN a client merges it, THEN the client keeps the marker.
Out of scope
- Changing the task or session state machine (no new task state; the task
remains
REVIEWwith aWAITING_FOR_INPUTsession after reconciliation). - Marking sessions or tasks
FAILEDon interruption; resumability behavior is unchanged. - Persisting the marker as a typed column; metadata is the single source.
- Office agent cards and the Office dashboard surface, which use their own status presentation.
- Reconstructing detached remote-work liveness after restart.
- A user-facing action to clear or dismiss the icon manually.
Related
- Task Runtime Cleanup — startup reconciliation semantics the marker hooks into.
- Sidebar Task Completion Icons — the shared task-row icon precedence this feature extends.
- Backend Runtime-State Ownership — startup publication that clears stale generating activity.