-- allium: 1
-- bDS Background Task Manager
-- Scope: core (Wave 1)
-- Distilled from: src/main/engine/TaskManager.ts

entity Task {
    name: String
    status: pending | running | completed | failed | cancelled
    progress: Decimal?              -- 0.0..1.0
    message: String?
    group_id: String?               -- Optional task grouping
    group_name: String?
    created_at: Timestamp

    transitions status {
        pending -> running
        running -> completed
        running -> failed
        running -> cancelled
    }
}

config {
    max_concurrent: Integer = 3
    progress_throttle: Duration = 250.milliseconds
}

invariant MaxConcurrency {
    -- At most max_concurrent tasks run simultaneously
    let running_tasks = Tasks where status = running
    running_tasks.count <= config.max_concurrent
}

invariant FifoQueue {
    -- When max concurrent reached, new tasks queue in FIFO order
    -- Queued tasks transition to running as slots open
}

rule SubmitTask {
    when: SubmitTaskRequested(name, work)
    let running_tasks = Tasks where status = running
    ensures: Task.created(name: name, status: pending)
    ensures:
        if running_tasks.count < config.max_concurrent:
            TaskStarted(task, work)
}

rule CompleteTask {
    when: TaskWorkCompleted(task)
    ensures: task.status = completed
    ensures: task.progress = 1.0
    ensures: NextQueuedTaskStarted()
}

rule FailTask {
    when: TaskWorkFailed(task, error_message)
    ensures: task.status = failed
    ensures: task.message = error_message
    ensures: NextQueuedTaskStarted()
}

rule CancelTask {
    when: CancelTaskRequested(task)
    requires: task.status = running or task.status = pending
    -- AbortController-based cancellation
    ensures: task.status = cancelled
    ensures: NextQueuedTaskStarted()
}

rule ReportProgress {
    when: ProgressReported(task, value, message)
    -- Progress events throttled to 250ms
    ensures: task.progress = value
    ensures: task.message = message
}

invariant ProgressThrottled {
    -- Progress update events are throttled to prevent UI flooding
    -- At most one progress event per 250ms per task
}

-- External tasks: lifecycle controlled by caller (e.g., renderer-side scripts)
rule RegisterExternalTask {
    when: RegisterExternalTaskRequested(name)
    ensures: Task.created(name: name, status: running)
    @guidance
        -- External tasks are not managed by the queue
        -- The caller is responsible for updating status
}
