RecoverRun terminalizes a needs_attention run and queues one fresh child to resume work.
( ctx context.Context, runID string, req RecoverRunRequest, actor ActorContext, )
| 280 | |
| 281 | // RecoverRun terminalizes a needs_attention run and queues one fresh child to resume work. |
| 282 | func (m *Service) RecoverRun( |
| 283 | ctx context.Context, |
| 284 | runID string, |
| 285 | req RecoverRunRequest, |
| 286 | actor ActorContext, |
| 287 | ) (*RetryRunResult, error) { |
| 288 | if err := m.requireForceRunAuthority(actor); err != nil { |
| 289 | return nil, err |
| 290 | } |
| 291 | normalized, err := normalizeRecoverRunRequest(req) |
| 292 | if err != nil { |
| 293 | return nil, err |
| 294 | } |
| 295 | source, taskRecord, err := m.loadRunWithTask(ctx, runID) |
| 296 | if err != nil { |
| 297 | return nil, err |
| 298 | } |
| 299 | if err := m.requireForceRunRate(actor, taskRecord.ID); err != nil { |
| 300 | return nil, err |
| 301 | } |
| 302 | if source.Status.Normalize() != TaskRunStatusNeedsAttention { |
| 303 | suggested := fmt.Sprintf("agh task inspect %s", source.ID) |
| 304 | if source.Status.Normalize() == TaskRunStatusFailed { |
| 305 | suggested = fmt.Sprintf("agh task retry %s", source.ID) |
| 306 | } |
| 307 | return nil, forceRunDiagnosticError( |
| 308 | diagnosticcontract.CodeTaskRunNotRecoverable, |
| 309 | "Task run cannot be recovered", |
| 310 | fmt.Sprintf( |
| 311 | "Run %s is %s; only needs_attention runs can be recovered.", |
| 312 | source.ID, |
| 313 | source.Status.Normalize(), |
| 314 | ), |
| 315 | diagnosticcontract.SeverityError, |
| 316 | suggested, |
| 317 | map[string]any{runEvidenceIDKey: source.ID, leaseStatusKey: string(source.Status.Normalize())}, |
| 318 | ErrInvalidStatusTransition, |
| 319 | ) |
| 320 | } |
| 321 | if err := m.requireRetryChainDepth(ctx, source); err != nil { |
| 322 | return nil, err |
| 323 | } |
| 324 | |
| 325 | result, err := m.store.RecoverTaskRun(ctx, RecoverRunMutation{ |
| 326 | SourceRunID: source.ID, |
| 327 | NewRunID: m.newID("run"), |
| 328 | Origin: actor.Origin, |
| 329 | Reason: normalized.Reason, |
| 330 | Metadata: normalized.Metadata, |
| 331 | QueuedAt: m.now().UTC(), |
| 332 | }) |
| 333 | if err != nil { |
| 334 | return nil, err |
| 335 | } |
| 336 | reconciledTask, err := m.reconcileTaskCascade(ctx, taskRecord.ID) |
| 337 | if err != nil { |
| 338 | return nil, err |
| 339 | } |
nothing calls this directly
no test coverage detected