5.9 KiB
5.9 KiB
status, created, owner, decision
| status | created | owner | decision |
|---|---|---|---|
| shipped | 2026-07-30 | kandev | docs/decisions/2026-07-30-runtime-task-state-before-running-event.md |
Runtime Task-State Publication Order
Why
Task surfaces combine the persisted task state with live session state. If a
session becomes RUNNING before its task is observably IN_PROGRESS, the
sidebar can briefly show a running spinner inside the Review state group even
though the task's workflow step and runtime are already active.
What
- For a non-Office, unarchived task whose session transitions into
RUNNING, Kandev reconciles the persisted task state toIN_PROGRESSbefore publishing that session'ssession.state_changedevent. - The same ordering applies when an answered
ask_user_question_kandevcall resumes the still-open agent turn directly, without launching a replacement prompt or waiting for a later runtime stream event. - When reconciliation changes the task state, observers receive
task.state_changedbeforesession.state_changedannouncesRUNNING. - The task and session publications share the task's existing per-task FIFO, so a session event cannot overtake an earlier task event when another task-scoped publication is already draining.
- The WebSocket gateway consumes both lifecycle notifications through one ordered NATS-style subscription, preserving that order when the event bus is remote; the in-memory event bus supports the same wildcard semantics.
- The task-state write remains guarded by the owning session's authoritative state. A concurrent clarification, cancellation, terminal transition, or archive prevents a stale runtime writer from promoting the task.
- Repeated stream activity for a session already in
RUNNINGdoes not cause repeated task-state writes or events. - The executor's post-start task-state reconciliation remains an eventual recovery path when the earlier reconciliation fails or is skipped.
- Existing sidebar state grouping, workflow-step rendering, status icons, and desktop/mobile composition remain unchanged.
Data model
This repair uses the existing persisted fields:
tasks.state, includingREVIEWandIN_PROGRESStask_sessions.state, includingWAITING_FOR_INPUT,STARTING, andRUNNING
No schema, enum, or persistence-format changes are introduced.
API surface
The existing WebSocket event names and payloads remain unchanged:
task.state_changedsession.state_changed
The ordering contract is defined by ADR-2026-07-30-runtime-task-state-before-running-event.
State machine
- A workflow transition may persist the target workflow step and use
REVIEWas a safe intermediate task state while no session owns active work. - When a prompt or runtime transition successfully changes an owning session to
RUNNING, the same lifecycle operation reconciles the task toIN_PROGRESSbefore exposing the new session state to clients. - When a clarification answer wakes a
WAITING_FOR_INPUTsession inside the open MCP call, the clarification lifecycle performs the guarded task reconciliation and publishes its task event before publishing theRUNNINGsession event. - When the turn settles and no sibling session is working, existing behavior
returns the task to
REVIEW.
Failure modes
- If guarded task reconciliation loses to a newer session/task transition, it does not overwrite the winner.
- If task reconciliation returns an error after the session transition is persisted, Kandev logs the error and still reports the truthful session state. The existing executor-success reconciliation remains available to heal the task state.
- If the task publication queue is already draining, the task-state and session-state events append in lifecycle order without waiting reentrantly on the active publication.
- Office task status remains controlled by the Office lifecycle and is not promoted by this runtime reconciliation.
Scenarios
- GIVEN a non-Office task in
REVIEWwith an owning session inWAITING_FOR_INPUT, WHEN the session accepts a new prompt and transitions toRUNNING, THENtasks.stateisIN_PROGRESSandtask.state_changedis published beforesession.state_changed(RUNNING). - GIVEN a non-Office task in
REVIEWwhose owning session isWAITING_FOR_INPUTinside an openask_user_question_kandevcall, WHEN the user answers and the same agent turn resumes, THEN the persisted task becomesIN_PROGRESS, WebSocket observers receivetask.state_changedbeforesession.state_changed(RUNNING), and the State-grouped sidebar moves the task out ofReviewwithout a page reload. - GIVEN the sidebar is grouped by State, WHEN it observes a session
transition to
RUNNING, THEN the task is not rendered with a running spinner inside theReviewgroup. - GIVEN a remote event bus delivers the two lifecycle events, WHEN the gateway forwards them to WebSocket clients, THEN the task-state notification is delivered before the running-session notification.
- GIVEN a session and task already in
RUNNING/IN_PROGRESS, WHEN additional tool or stream events arrive, THEN no redundant task-state write or state-change event is produced. - GIVEN a clarification or cancellation changes the session before guarded
task reconciliation commits, WHEN the stale runtime transition resumes,
THEN the task is not promoted to
IN_PROGRESS. - GIVEN an archived or Office task, WHEN a session reports runtime activity, THEN this repair does not rewrite its task state.
Out of scope
- Changing how sidebar State groups are derived or labeled.
- Inferring persisted task state in the frontend from session events.
- Changing workflow-step transitions, session-state enums, WebSocket payloads, Office task-state ownership, or task status icons.
- Adding new desktop or mobile layout, navigation, or touch behavior.