UpdateTask applies one mutable patch while preserving immutable identity and structural fields under manager control.
(ctx context.Context, id string, patch Patch, actor ActorContext)
| 461 | // UpdateTask applies one mutable patch while preserving immutable identity and |
| 462 | // structural fields under manager control. |
| 463 | func (m *Service) UpdateTask(ctx context.Context, id string, patch Patch, actor ActorContext) (*Task, error) { |
| 464 | if err := requireWriteAuthority(actor); err != nil { |
| 465 | return nil, err |
| 466 | } |
| 467 | |
| 468 | trimmedID := strings.TrimSpace(id) |
| 469 | if trimmedID == "" { |
| 470 | return nil, fmt.Errorf("%w: task id is required", ErrValidation) |
| 471 | } |
| 472 | normalizedPatch, err := normalizeTaskPatch(patch) |
| 473 | if err != nil { |
| 474 | return nil, err |
| 475 | } |
| 476 | if normalizedPatch.NetworkChannel != nil { |
| 477 | if err := m.validateNetworkChannel("task_patch.network_channel", *normalizedPatch.NetworkChannel); err != nil { |
| 478 | return nil, err |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | current, err := m.store.GetTask(ctx, trimmedID) |
| 483 | if err != nil { |
| 484 | return nil, err |
| 485 | } |
| 486 | |
| 487 | updated, changedFields := applyTaskPatch(current, normalizedPatch) |
| 488 | if len(changedFields) == 0 { |
| 489 | return ¤t, nil |
| 490 | } |
| 491 | |
| 492 | dependencies, err := m.store.ListDependencies(ctx, trimmedID) |
| 493 | if err != nil { |
| 494 | return nil, err |
| 495 | } |
| 496 | runs, err := m.store.ListTaskRuns(ctx, RunQuery{TaskID: trimmedID}) |
| 497 | if err != nil { |
| 498 | return nil, err |
| 499 | } |
| 500 | |
| 501 | canonicalStatus, err := m.canonicalTaskStatus(ctx, updated, dependencies, runs) |
| 502 | if err != nil { |
| 503 | return nil, err |
| 504 | } |
| 505 | updated.Status = canonicalStatus |
| 506 | updated.UpdatedAt = m.now().UTC() |
| 507 | if err := m.store.UpdateTask(ctx, updated); err != nil { |
| 508 | return nil, err |
| 509 | } |
| 510 | if err := m.recordTaskEvent(ctx, updated.ID, "", taskEventUpdated, actor, updatedTaskPayload{ |
| 511 | ChangedFields: append([]string(nil), changedFields...), |
| 512 | Status: updated.Status, |
| 513 | }); err != nil { |
| 514 | return nil, err |
| 515 | } |
| 516 | |
| 517 | return &updated, nil |
| 518 | } |
| 519 | |
| 520 | // CancelTask propagates manager-owned cancellation through the target task, |
nothing calls this directly
no test coverage detected