Give an operator one way to retry a terminal task
A task that reached the router's MaxAttempts was permanently terminal.
TaskReleased only ever increments Attempt, TaskCorrected could not touch it,
and no HTTP route emitted a correction at all. The only way to work an
exhausted issue again was to invent a second task for it, which defeats
(source, external_id) dedupe and abandons the task's own history.
POST /v1/tasks/{id}/retry, full-control surfaces only. It requires the task
to be failed, unleased, and failed with reason retry_limit: restoring a retry
budget is not an answer to a failure that was not the budget running out. The
effect is one TaskCorrected naming that failure, setting state queued and
attempt 0 and clearing next_retry_at, failure_class and last_error. Task id,
source pair, goal, acceptance, decisions, work phase and artifact refs all
stay, and the original failure events stay in the log.
operation_id is required and makes the call idempotent, so a repeated request
cannot reset an attempt that has since started running.
This is RetryTask, not a generic correction endpoint: arbitrary task mutation
over HTTP is a different and much larger authority. It also does not address
F9, which is an operator releasing a lease someone else owns.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -437,6 +437,23 @@ func ValidatePayload(typ string, p map[string]any) error {
|
||||
return fmt.Errorf("%w: state invalid", ErrInvalid)
|
||||
}
|
||||
}
|
||||
if v, ok := p["attempt"]; ok {
|
||||
n, ok := v.(float64)
|
||||
if !ok || n < 0 || n != float64(int(n)) {
|
||||
return fmt.Errorf("%w: attempt must be a non-negative whole number", ErrInvalid)
|
||||
}
|
||||
}
|
||||
if v, ok := p["next_retry_at"]; ok {
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w: next_retry_at must be a string", ErrInvalid)
|
||||
}
|
||||
if s != "" {
|
||||
if _, err := time.Parse(time.RFC3339, s); err != nil {
|
||||
return fmt.Errorf("%w: next_retry_at must be RFC3339 or empty", ErrInvalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(p) < 2 {
|
||||
return fmt.Errorf("%w: correction must change at least one field", ErrInvalid)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user