Skip to main content

Task

Struct Task 

Source
pub struct Task {
Show 15 fields pub schema: u32, pub id: String, pub title: String, pub instruction: String, pub repo: PathBuf, pub source: Source, pub priority: i32, pub solo: bool, pub status: TaskStatus, pub attempts: usize, pub runs: Vec<String>, pub last_error: Option<String>, pub hold_reason: Option<String>, pub created_at: Timestamp, pub updated_at: Timestamp,
}
Expand description

One unit of work.

Fields§

§schema: u32

On-disk format version.

§id: String

Task id, e.g. 20260902-140501-a1b2.

§title: String

One line, for lists and notifications.

§instruction: String

The task itself, handed to the graph verbatim.

§repo: PathBuf

Repository to work in.

§source: Source

Who asked.

§priority: i32

Higher runs first; ties break oldest-first so nothing starves.

§solo: bool

Run this task alone: one implementer, no panel of judges to convince.

#[serde(default)] so a queue file written before this field existed still reads, as false - the ordinary multi-candidate competition, unchanged. A task set to solo still runs the whole graph; only the candidate count the daemon builds it with changes, and crate::graph::Runner already collapses a single-candidate run to implement → review → gate → merge on its own (see crate::graph::Runner::review’s doc), so nothing about judging, deliberation or voting had to change to support this.

§status: TaskStatus

Current state.

§attempts: usize

How many times this task has been claimed.

§runs: Vec<String>

Runs this task has produced, oldest first.

§last_error: Option<String>

Why the last attempt did not land.

§hold_reason: Option<String>

What a human hold is waiting on.

None covers both the ordinary cases: a hold the loop makes itself (out of attempts, or the disk gate closed) explains itself through Task::last_error instead, and a human hold nobody bothered to explain is still a valid hold. The queue has no way to express a dependency between two tasks, so on the occasions a hold really is “wait for that other task first”, this is the only place that reason survives - see Task::hold and Task::release.

#[serde(default)] so a queue file written before this field existed still reads, with no reason recorded rather than a parse error.

§created_at: Timestamp

When the task was filed.

§updated_at: Timestamp

Last change to this file.

Implementations§

Source§

impl Task

Source

pub fn new( title: String, instruction: String, repo: PathBuf, source: Source, ) -> Self

File a new task. Persist it with Queue::put.

Source

pub fn short(&self) -> &str

Short form used in reports, matching a run’s short id.

Source

pub fn start(&mut self, run: String)

Record that a run has started for this task.

Source

pub fn succeed(&mut self)

Record a successful run.

Both magi task done and POST /api/queue/{id}/done can close a held task directly, with no release in between, so this clears hold_reason the same way Task::release does. Otherwise a task held for “waiting on 3ed9” and then closed as done without ever being released would still read as waiting on something in magi task show and on its card, after it no longer is.

Source

pub fn fail(&mut self, why: impl Into<String>, max_attempts: usize)

Record a failed attempt. Out of attempts means held for a human, rather than retried until the money runs out.

Source

pub fn stall(&mut self, why: impl Into<String>)

Record an attempt that failed for a reason the task is not responsible for - the agent CLIs ran out of quota and the judging panel collapsed.

This refunds the attempt on purpose. A quota window closing at 4am must not spend the backlog’s retry budget: the operator would come back to a queue of held tasks that were never actually judged, and would have to release every one by hand to find out which had a real problem. The task goes back to Failed, which the loop retries, so a reset quota picks the work up where it stopped.

Source

pub fn hold(&mut self, reason: Option<String>)

Take this task out of the loop’s reach without deleting it.

reason replaces whatever was recorded before when it is given. Passing None - the loop’s own holds do this - leaves any existing reason alone, so a machine-initiated hold cannot erase what a human wrote down about a previous one.

Source

pub fn set_priority(&mut self, priority: i32) -> Result<()>

Change how urgently this task should run next.

Refused once the task is running: priority only feeds the sort Queue::next_runnable does over tasks waiting to be claimed, and a running task has already left that pool. Accepting the write anyway would look like it worked while changing nothing until - and unless - this attempt fails and the task becomes runnable again, which is a surprise the phone should not hand back as a success.

Source

pub fn edit(&mut self, title: String, instruction: String) -> Result<()>

Replace this task’s title and instruction wholesale.

Restricted to queued and held. A running task’s instruction has already been handed to the graph, so a run in flight and the file on disk must not be allowed to disagree about what was asked; a done or failed task is a record of what actually happened and editing it after the fact would falsify that record. id, created_at, source, and runs are left untouched on purpose - an edit stands in for “delete and refile”, and keeping the id, the timestamp, the attribution, and the run history is the entire reason it exists instead.

Source

pub fn handed_off(&mut self, why: impl Into<String>)

Record a run that produced a pull request without merging it.

The task is held rather than retried, and it costs no further attempt either way. The work the task asked for exists: it is sitting on a branch, in a pull request, waiting for CI or for a person. Retrying would spend the whole competition budget a second time and then race a second branch against the pull request the first one opened - which is exactly what happened to run 01c2, whose finished and green pull request was re-competed from scratch four seconds after it opened.

A pull request nobody merged is a request for a person, not a failure.

Source

pub fn release(&mut self)

Put a held or finished task back in line, with its attempt count reset so a release is a real second chance rather than an instant re-hold. The run history is kept: attempts reset, evidence does not.

Trait Implementations§

Source§

impl Clone for Task

Source§

fn clone(&self) -> Task

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Task

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Task

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Task

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl Freeze for Task

§

impl RefUnwindSafe for Task

§

impl Send for Task

§

impl Sync for Task

§

impl Unpin for Task

§

impl UnsafeUnpin for Task

§

impl UnwindSafe for Task

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more