package storage // Status — статус задачи (state machine). type Status string const ( StatusDraft Status = "draft" // только что создана StatusCollecting Status = "collecting" // аналитик собирает детали StatusReady Status = "ready" // черновик готов, ждёт запуска StatusRunning Status = "running" // opencode работает StatusSuccess Status = "success" // задача выполнена StatusFailed Status = "failed" // ошибка выполнения StatusTimeout Status = "timeout" // таймаут opencode StatusCancelled Status = "cancelled" // отменена пользователем StatusAborted Status = "aborted" // сбой сбора, черновик выброшен StatusClosed Status = "closed" // закрыта вручную ) // AllStatuses — все возможные статусы для валидации. var AllStatuses = []Status{ StatusDraft, StatusCollecting, StatusReady, StatusRunning, StatusSuccess, StatusFailed, StatusTimeout, StatusCancelled, StatusAborted, StatusClosed, } // validTransitions задаёт разрешённые переходы статусов. var validTransitions = map[Status][]Status{ StatusDraft: {StatusCollecting, StatusCancelled, StatusAborted}, StatusCollecting: {StatusReady, StatusDraft, StatusCancelled, StatusAborted}, StatusReady: {StatusRunning, StatusCancelled, StatusAborted, StatusClosed}, StatusRunning: {StatusSuccess, StatusFailed, StatusTimeout, StatusCancelled}, StatusSuccess: {StatusClosed}, StatusFailed: {StatusReady, StatusClosed, StatusCancelled}, // retry StatusTimeout: {StatusReady, StatusClosed, StatusCancelled}, // retry StatusCancelled: {StatusClosed}, StatusAborted: {StatusClosed}, StatusClosed: {}, // терминальный } // IsValidTransition проверяет, допустим ли переход from → to. func IsValidTransition(from, to Status) bool { allowed, ok := validTransitions[from] if !ok { return false } for _, s := range allowed { if s == to { return true } } return false } // IsTerminal возвращает true, если статус терминальный. func IsTerminal(s Status) bool { return s == StatusSuccess || s == StatusCancelled || s == StatusAborted || s == StatusClosed } // Task — запись задачи в БД. type Task struct { ID int64 `json:"id"` ChatID string `json:"chat_id"` // tg:// Title string `json:"title"` Goal string `json:"goal"` Repo string `json:"repo"` Why string `json:"why"` AC string `json:"ac"` // acceptance criteria TaskTag string `json:"task_tag"` // UUID, стабильный на всю жизнь Status Status `json:"status"` CreatedAt SQLiteTime `json:"created_at"` UpdatedAt SQLiteTime `json:"updated_at"` } // Trace — запись трассировки выполнения. type TraceStatus string const ( TraceRunning TraceStatus = "running" TraceSuccess TraceStatus = "success" TraceFailed TraceStatus = "failed" TraceTimeout TraceStatus = "timeout" ) // Trace — лог одного субагента. type Trace struct { ID int64 `json:"id"` TaskID int64 `json:"task_id"` Agent string `json:"agent"` // analyst | researcher | dev | reviewer SessionID string `json:"session_id"` // opencode session_id Prompt string `json:"prompt"` Output string `json:"output"` // полный NDJSON или summary Status TraceStatus `json:"status"` StartedAt SQLiteTime `json:"started_at"` FinishedAt NullSQLiteTime `json:"finished_at,omitempty"` } // TaskFilter — параметры фильтрации списка задач. type TaskFilter struct { ChatID string Status Status Limit int Offset int }