pub const SCHEMA: u32 = 5;Expand description
On-disk format for a queued task. Bumped when a field’s meaning changes.
5: added Task::triage_applied, the ids of triage questions whose
answer has already been applied to this task. A “resume” answer used to
leave no trace (Task::release clears Task::hold_reason, which was
the only place the applied marker lived), so when the released task failed
its attempts and went back to held, the next idle pass found the same
answered question “not applied” and released it again with attempts reset
to 0 - the max_attempts bound never held. #[serde(default)] so an older
record reads as empty. A task already looping when this build arrives has
no record, so it is released once more, recorded, and then stays held.
4: added Task::blocked_from, the status a task had the moment it
became TaskStatus::Blocked, so Task::unblock restores it instead
of always landing on TaskStatus::Queued. Without it, a task a human
or crate::triage had deliberately left TaskStatus::Held — machine
or manual — would lose that the instant crate::conduct blocked it on a
follow-up question, and come back Queued the moment the question was
answered, regardless of what the answer said: exactly the loop where a
task the operator told to stay held instead re-enters the competition
queue every time someone answers a question about it. #[serde(default)]
so an older record reads as None; Task::unblock then falls back to
inferring Held from surviving hold evidence (Task::hold_reason /
Task::hold_source, never cleared by Task::block) rather than
guessing Queued outright — see Task::unblock’s own doc.
3: added HoldSource so conductor recovery cannot release a hold an
operator deliberately placed. Old records default to None and are
protected as operator-held until an explicit release; the safe direction
when their author was never recorded.
2: added TaskStatus::Blocked, Task::blocked_by and
Task::block_reason (crate::conduct’s decisions) and
Task::answers (operator answers carried forward to the next
conductor prompt and the next run’s instruction). All three are
#[serde(default)], so [read_path] accepts anything up to and
including this schema rather than only an exact match — a task written
by a build that only knew about schema 1 has nothing to say about
blocking or answers, and defaulting those fields is exactly as good a
reading as a value that build never had a chance to write.