package agenttask import ( "context" "fmt" "reflect" "iop/packages/go/agentguard" "iop/packages/go/agentpolicy" ) func (m *Manager) runWork( ctx context.Context, projectID ProjectID, workID WorkUnitID, ) error { for { project, work, err := m.loadWork(ctx, projectID, workID) if err != nil { return err } switch work.State { case WorkStateReviewing: if work.Submission == nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerArtifactMismatch, Message: "reviewing work has no durable submission identity", }) return nil } rework, reviewErr := m.reviewSubmission(ctx, project, work, *work.Submission) if reviewErr != nil || !rework { return reviewErr } continue case WorkStateReady: default: return nil } if err := m.changeWork(ctx, projectID, workID, func(work *WorkRecord) error { return transitionWork(work, WorkStatePreparing) }); err != nil { return err } project, work, err = m.loadWork(ctx, projectID, workID) if err != nil { return err } target, err := m.selectTarget(ctx, project, work) if err != nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerSelectionFailed, Message: err.Error(), Retryable: true, }) return nil } if err := validateTarget(project, target); err != nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerInvalidIdentity, Message: err.Error(), }) return nil } isolation, err := m.isolation.Prepare(ctx, IsolationRequest{ Project: project, Work: work, Target: target, IdempotencyKey: dispatchKey(projectID, workID, work.Attempt) + "/isolation", }) if err != nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerIsolationFailed, Message: err.Error(), Retryable: true, }) return nil } admissionRequest, isolationIdentity, err := validatePreparedIsolation(project, work, target, isolation) if err != nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerIsolationFailed, Message: err.Error(), }) return nil } admission := agentguard.Admit(admissionRequest) if !admission.Allowed() { detail := "workspace admission denied" if admission.Blocker != nil { detail = string(admission.Blocker.Code) + ": " + admission.Blocker.Message } m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerAdmissionFailed, Message: detail, }) return nil } lease, err := m.scheduler.Acquire(ctx, DispatchCandidate{ ProjectID: projectID, WorkspaceID: project.WorkspaceID, WorkUnitID: workID, AttemptID: work.AttemptID, Target: target, }) if err != nil { if ctx.Err() != nil { _ = m.changeWork(context.WithoutCancel(ctx), projectID, workID, func(work *WorkRecord) error { return transitionWork(work, WorkStateReady) }) return ctx.Err() } m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerProviderCapacity, Message: err.Error(), Retryable: true, }) return nil } err = m.changeWork(ctx, projectID, workID, func(work *WorkRecord) error { if err := transitionWork(work, WorkStateDispatching); err != nil { return err } work.Target = &target work.Isolation = &isolationIdentity if work.Locators == nil { work.Locators = make(map[LocatorKind]LocatorRecord) } work.Locators[LocatorOverlay] = locatorForIsolation(project, *work, isolationIdentity) return nil }) if err != nil { lease.Release() return err } project, work, err = m.loadWork(ctx, projectID, workID) if err != nil { lease.Release() return err } var cmdID CommandID var wfRev WorkflowRevision if project.Intent != nil { cmdID = project.Intent.CommandID wfRev = project.Intent.WorkflowRevision } m.emit(ctx, Event{ Type: EventDispatchStarted, ProjectID: projectID, WorkspaceID: project.WorkspaceID, WorkUnitID: workID, CommandID: cmdID, WorkflowRevision: wfRev, AttemptID: work.AttemptID, Ordinal: work.DispatchOrdinal, State: work.State, ProviderID: target.ProviderID, ProfileID: target.ProfileID, WriteSetKind: work.Unit.WriteSetKind, IsolationMode: work.Unit.IsolationMode, }) var invocation ProviderInvocation var launch ProviderLaunch confinementBinding := isolation.Confinement.Binding() dispatchRequest := DispatchRequest{ Project: project, Work: work, Target: target, AdmissionRequest: admissionRequest, Permit: admission.Permit, Workspace: *admission.Workspace, Confinement: isolation.Confinement, IdempotencyKey: dispatchKey(projectID, workID, work.Attempt), } validation, invokeErr := agentguard.Invoke( ctx, admission.Permit, admissionRequest, func(invokeCtx context.Context, workspace agentguard.CanonicalWorkspace) error { if workspace.ConfinementRevision != isolation.Confinement.Revision() { return fmt.Errorf( "agenttask: permit confinement revision does not match the executable proof", ) } if err := isolation.Confinement.Validate(confinementBinding); err != nil { return fmt.Errorf( "agenttask: executable confinement proof became invalid before invocation: %w", err, ) } dispatchRequest.Workspace = workspace prepared, err := m.invoker.Prepare(invokeCtx, dispatchRequest) if err != nil { return err } if prepared == nil { return fmt.Errorf("agenttask: provider returned a nil launch plan") } launch = prepared command := launch.Command() started, err := isolation.Confinement.Start(invokeCtx, command) if err != nil { return fmt.Errorf("agenttask: start provider through executable confinement: %w", err) } if err := validateStartedConfinement(started); err != nil { if started != nil { _ = started.Abort() } return err } invocation, err = launch.BindStarted(started) if err != nil { _ = started.Abort() return fmt.Errorf("agenttask: bind confined provider child: %w", err) } if invocation == nil { _ = started.Abort() return fmt.Errorf("agenttask: provider bound a nil invocation handle") } return nil }, ) if !validation.Allowed() { lease.Release() detail := "admission permit became invalid before invocation" if validation.Blocker != nil { detail = string(validation.Blocker.Code) + ": " + validation.Blocker.Message } m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerAdmissionFailed, Message: detail, }) return nil } if invokeErr != nil { lease.Release() if ctx.Err() != nil { return ctx.Err() } m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerInvocationFailed, Message: "provider launch failed before a normalized invocation was available", Retryable: true, }) return nil } if launch == nil || invocation == nil { lease.Release() m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerInvocationFailed, Message: "provider launch did not bind an invocation handle", }) return nil } invocationLocators := invocation.Locators() if err := validateInvocationLocators(project, work, invocationLocators); err != nil { _ = invocation.Cancel(context.WithoutCancel(ctx)) lease.Release() m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerStaleCheckpoint, Message: err.Error(), }) return nil } if err := m.changeWork(ctx, projectID, workID, func(work *WorkRecord) error { for _, locator := range invocationLocators { work.Locators[locator.Kind] = locator } return nil }); err != nil { _ = invocation.Cancel(context.WithoutCancel(ctx)) lease.Release() return err } submission, invokeErr := invocation.Wait(ctx) lease.Release() if invokeErr != nil { if ctx.Err() != nil { return ctx.Err() } handled, continueWork, continuationErr := m.continueAfterInvocationFailure( ctx, project, work, target, invocation, ) if continuationErr != nil { return continuationErr } if handled { if continueWork { continue } return nil } m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerInvocationFailed, Message: "provider invocation failed without a normalized failure observation", Retryable: true, }) return nil } project, work, err = m.loadWork(ctx, projectID, workID) if err != nil { return err } if err := validateSubmission(project, work, submission); err != nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerArtifactMismatch, Message: err.Error(), }) return nil } if !submission.Ready { m.blockWork(ctx, projectID, workID, WorkStateBlocked, Blocker{ Code: BlockerSubmissionIncomplete, Message: "worker submission did not pass the provider-neutral completeness gate", }) return nil } if blocker := m.gateSubmissionEvidence(ctx, project, work, submission); blocker != nil { m.blockWork(ctx, projectID, workID, WorkStateBlocked, *blocker) return nil } if err := m.changeWork(ctx, projectID, workID, func(work *WorkRecord) error { if err := transitionWork(work, WorkStateSubmitted); err != nil { return err } work.Submission = &submission for _, locator := range submission.Locators { work.Locators[locator.Kind] = locator } resetFailure(work, FailureStageDispatch) work.ContinuationTarget = nil return nil }); err != nil { return err } m.emit(ctx, Event{ Type: EventSubmissionAccepted, ProjectID: projectID, WorkspaceID: project.WorkspaceID, WorkUnitID: workID, CommandID: cmdID, WorkflowRevision: wfRev, AttemptID: work.AttemptID, Ordinal: work.DispatchOrdinal, Detail: string(submission.ArtifactID), }) if err := m.changeWork(ctx, projectID, workID, func(work *WorkRecord) error { return transitionWork(work, WorkStateReviewing) }); err != nil { return err } project, work, err = m.loadWork(ctx, projectID, workID) if err != nil { return err } rework, err := m.reviewSubmission(ctx, project, work, submission) if err != nil || !rework { return err } } } // selectTarget preserves a policy-authorized continuation target across a // crash or pre-invocation retry. New work still goes through the ordinary // selector; no continuation target is inferred from a previous failure. func (m *Manager) selectTarget( ctx context.Context, project ProjectRecord, work WorkRecord, ) (ExecutionTarget, error) { if work.ContinuationTarget != nil { return *work.ContinuationTarget, nil } return m.selector.Select(ctx, SelectionRequest{Project: project, Work: work}) } func (m *Manager) continueAfterInvocationFailure( ctx context.Context, project ProjectRecord, work WorkRecord, current ExecutionTarget, invocation ProviderInvocation, ) (handled bool, continueWork bool, err error) { observed, ok := invocation.(FailureObservedInvocation) if !ok { return false, false, nil } observation := agentpolicy.SanitizeAttemptObservation( observed.FailureObservation(), m.clock.Now(), ) if !observationMatchesTarget(observation, current) { observation.Quota = agentpolicy.CorruptQuotaObservation() } source, ok := m.selector.(FailureContinuationPolicySource) if !ok { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyUnavailable, Message: "no declared failure continuation policy is available", }, ) } policy, policyErr := source.ContinuationPolicy(ctx, FailureContinuationPolicyRequest{ Project: project, Work: work, CurrentTarget: current, Observation: observation, }) if policyErr != nil { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "failure continuation policy rejected the observation", }, ) } request, candidateTargets, buildErr := m.continuationRequest( project, work, current, observation, policy, ) if buildErr != nil { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "failure continuation policy inputs are invalid", }, ) } decision, decisionErr := agentpolicy.DecideContinuation(request) if decisionErr != nil { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "common failure continuation policy rejected its inputs", }, ) } switch decision.Action { case agentpolicy.ContinuationBlock: if decision.Blocker == "" { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "failure continuation policy returned an invalid block decision", }, ) } return m.persistContinuation( ctx, project, work, current, observation, decision.Action, nil, blockerFromContinuation(decision.Blocker), ) case agentpolicy.ContinuationRetry: if !targetMatchesIdentity(current, decision.Target) { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "failure continuation policy returned an invalid next target", }, ) } return m.persistContinuation( ctx, project, work, current, observation, decision.Action, ¤t, Blocker{}, ) case agentpolicy.ContinuationFailover: next, exists := candidateTargets[decision.Target] if !exists || sameExecutionTarget(next, current) { return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "common failure policy selected an unknown failover target", }, ) } return m.persistContinuation( ctx, project, work, current, observation, decision.Action, &next, Blocker{}, ) default: return m.persistContinuation( ctx, project, work, current, observation, agentpolicy.ContinuationBlock, nil, Blocker{ Code: BlockerFailurePolicyDenied, Message: "failure continuation policy returned an unsupported action", }, ) } } func (m *Manager) continuationRequest( project ProjectRecord, work WorkRecord, current ExecutionTarget, observation agentpolicy.AttemptObservation, source FailureContinuationPolicy, ) (agentpolicy.ContinuationRequest, map[agentpolicy.TargetIdentity]ExecutionTarget, error) { currentIdentity := executionTargetIdentity(current) used := make([]agentpolicy.TargetIdentity, 0, len(work.AttemptObservations)) seenUsed := make(map[agentpolicy.TargetIdentity]struct{}, len(work.AttemptObservations)) for _, record := range work.AttemptObservations { identity := executionTargetIdentity(record.Target) if _, duplicate := seenUsed[identity]; duplicate { continue } seenUsed[identity] = struct{}{} used = append(used, identity) } candidates := make([]agentpolicy.ContinuationCandidate, 0, len(source.Candidates)) candidateTargets := make(map[agentpolicy.TargetIdentity]ExecutionTarget, len(source.Candidates)) for _, candidate := range source.Candidates { if err := validateTarget(project, candidate.Target); err != nil { return agentpolicy.ContinuationRequest{}, nil, err } identity := executionTargetIdentity(candidate.Target) if _, duplicate := candidateTargets[identity]; duplicate { return agentpolicy.ContinuationRequest{}, nil, fmt.Errorf( "agenttask: continuation policy repeats a candidate target", ) } quota := agentpolicy.SanitizeQuotaObservation(candidate.Quota) if quota.Validity != agentpolicy.ObservationCorrupt && (quota.Adapter != candidate.Target.ProviderID || quota.Target != candidate.Target.ProfileID) { quota = agentpolicy.CorruptQuotaObservation() } candidateTargets[identity] = candidate.Target candidates = append(candidates, agentpolicy.ContinuationCandidate{ Target: identity, Eligible: candidate.Eligible, Quota: quota, }) } return agentpolicy.ContinuationRequest{ Policy: source.Policy, Current: currentIdentity, Candidates: candidates, Used: used, Budget: m.pendingFailureBudget(work), Observation: observation, }, candidateTargets, nil } func (m *Manager) persistContinuation( ctx context.Context, project ProjectRecord, failedWork WorkRecord, current ExecutionTarget, observation agentpolicy.AttemptObservation, action agentpolicy.ContinuationAction, next *ExecutionTarget, blocker Blocker, ) (handled bool, continueWork bool, err error) { var outcomeBlocker Blocker var nextAttempt AttemptID continued := false err = m.changeWork(ctx, project.ProjectID, failedWork.Unit.ID, func(work *WorkRecord) error { if work.AttemptID != failedWork.AttemptID || work.State != WorkStateDispatching { return fmt.Errorf("agenttask: failed work changed before continuation was persisted") } if err := appendAttemptObservation(work, current, observation); err != nil { return err } if action == agentpolicy.ContinuationBlock { outcomeBlocker = m.recordFailure(work, FailureStageDispatch, blocker) if err := transitionWork(work, WorkStateBlocked); err != nil { return err } work.Blocker = &outcomeBlocker return nil } outcomeBlocker = m.recordFailure(work, FailureStageDispatch, Blocker{ Code: BlockerInvocationFailed, Message: "provider execution failed; continuation was policy-authorized", Retryable: true, }) if outcomeBlocker.Code == BlockerFailureBudgetExhausted { if err := transitionWork(work, WorkStateBlocked); err != nil { return err } work.Blocker = &outcomeBlocker return nil } if next == nil { return fmt.Errorf("agenttask: continuation has no next target") } if err := transitionWork(work, WorkStateReady); err != nil { return err } work.Attempt++ work.AttemptID = attemptID(work.Unit.ID, work.Attempt) target := *next work.Target = nil work.ContinuationTarget = &target work.Isolation = nil work.Submission = nil work.Review = nil work.ChangeSet = nil work.Integration = nil work.Locators = make(map[LocatorKind]LocatorRecord) work.Blocker = nil nextAttempt = work.AttemptID continued = true return nil }) if err != nil { return true, false, err } if continued { var commandID CommandID var workflowRevision WorkflowRevision if project.Intent != nil { commandID = project.Intent.CommandID workflowRevision = project.Intent.WorkflowRevision } m.emit(ctx, Event{ Type: EventFollowup, ProjectID: project.ProjectID, WorkspaceID: project.WorkspaceID, WorkUnitID: failedWork.Unit.ID, CommandID: commandID, WorkflowRevision: workflowRevision, AttemptID: nextAttempt, Ordinal: failedWork.DispatchOrdinal, Detail: string(action), }) return true, true, nil } m.emit(ctx, Event{ Type: EventBlocked, ProjectID: project.ProjectID, WorkspaceID: project.WorkspaceID, WorkUnitID: failedWork.Unit.ID, AttemptID: failedWork.AttemptID, Ordinal: failedWork.DispatchOrdinal, State: WorkStateBlocked, Detail: string(outcomeBlocker.Code), }) return true, false, nil } func (m *Manager) pendingFailureBudget(work WorkRecord) agentpolicy.FailureBudget { budget := work.FailureBudgets[FailureStageDispatch] limit := budget.Limit if limit == 0 { limit = m.config.MaxFailureAttempts } used := budget.Consecutive if used < limit { used++ } return agentpolicy.FailureBudget{Used: used, Limit: limit} } func appendAttemptObservation( work *WorkRecord, target ExecutionTarget, observation agentpolicy.AttemptObservation, ) error { record := AttemptObservationRecord{ AttemptID: work.AttemptID, Target: target, Observation: observation.Clone(), } for _, existing := range work.AttemptObservations { if existing.AttemptID != record.AttemptID { continue } if reflect.DeepEqual(existing, record) { return nil } return fmt.Errorf("agenttask: a different failure observation already exists for this attempt") } work.AttemptObservations = append(work.AttemptObservations, record) return nil } func observationMatchesTarget( observation agentpolicy.AttemptObservation, target ExecutionTarget, ) bool { if observation.Quota.Validity == agentpolicy.ObservationCorrupt { return true } return observation.Quota.Adapter == target.ProviderID && observation.Quota.Target == target.ProfileID } func targetMatchesIdentity( target ExecutionTarget, identity agentpolicy.TargetIdentity, ) bool { return target.ProviderID == identity.ProviderID && target.ModelID == identity.ModelID && target.ProfileID == identity.ProfileID && target.ProfileRevision == identity.ProfileRevision } func executionTargetIdentity(target ExecutionTarget) agentpolicy.TargetIdentity { return agentpolicy.TargetIdentity{ ProviderID: target.ProviderID, ModelID: target.ModelID, ProfileID: target.ProfileID, ProfileRevision: target.ProfileRevision, } } func sameExecutionTarget(left, right ExecutionTarget) bool { return left.ProviderID == right.ProviderID && left.ModelID == right.ModelID && left.ProfileID == right.ProfileID && left.ProfileRevision == right.ProfileRevision && left.ConfigRevision == right.ConfigRevision && left.Capacity == right.Capacity } func blockerFromContinuation(code agentpolicy.ContinuationBlockerCode) Blocker { switch code { case agentpolicy.ContinuationBlockerUnknownQuota: return Blocker{Code: BlockerFailureObservationUnknown, Message: "quota observation is unknown"} case agentpolicy.ContinuationBlockerStaleObservation: return Blocker{Code: BlockerFailureObservationStale, Message: "quota observation is stale"} case agentpolicy.ContinuationBlockerCorruptObservation: return Blocker{Code: BlockerFailureObservationCorrupt, Message: "quota observation is corrupt"} case agentpolicy.ContinuationBlockerUnknownFailure: return Blocker{Code: BlockerFailureUnknown, Message: "runtime failure is unknown"} case agentpolicy.ContinuationBlockerBudgetExhausted: return Blocker{Code: BlockerFailureBudgetExhausted, Message: "failure budget is exhausted"} case agentpolicy.ContinuationBlockerNoAlternate: return Blocker{Code: BlockerNoEligibleFailover, Message: "no eligible unused failover target remains"} default: return Blocker{Code: BlockerFailurePolicyDenied, Message: "failure is not declared by policy"} } } func validateStartedConfinement(started StartedConfinement) error { if started == nil { return fmt.Errorf("agenttask: executable confinement returned a nil started handle") } if started.Child() == nil { return fmt.Errorf("agenttask: executable confinement returned a started handle without a child") } if started.Stdin() == nil || started.Stdout() == nil || started.Stderr() == nil { return fmt.Errorf("agenttask: executable confinement returned incomplete child I/O") } return nil } func validateInvocationLocators( project ProjectRecord, work WorkRecord, locators []LocatorRecord, ) error { if len(locators) == 0 { return fmt.Errorf("agenttask: provider invocation returned no durable process or session locator") } seen := make(map[LocatorKind]struct{}, len(locators)) for _, locator := range locators { if locator.Kind != LocatorProcess && locator.Kind != LocatorSession { return fmt.Errorf("agenttask: provider returned unsupported %q invocation locator", locator.Kind) } if _, duplicate := seen[locator.Kind]; duplicate { return fmt.Errorf("agenttask: provider returned duplicate %q invocation locator", locator.Kind) } seen[locator.Kind] = struct{}{} if err := validateLocator(project, work, locator); err != nil { return err } if existing, ok := work.Locators[locator.Kind]; ok && !reflect.DeepEqual(existing, locator) { return fmt.Errorf("agenttask: provider replaced the durable %q locator", locator.Kind) } } return nil } func validateTarget(project ProjectRecord, target ExecutionTarget) error { for field, value := range map[string]string{ "provider": target.ProviderID, "model": target.ModelID, "profile": target.ProfileID, "profile_revision": target.ProfileRevision, } { if err := validateIdentity(field, value); err != nil { return err } } if project.Intent == nil || target.ConfigRevision != project.Intent.ConfigRevision { return fmt.Errorf("agenttask: selected target config revision does not match manual start") } if target.Capacity <= 0 { return fmt.Errorf("agenttask: selected target capacity must be positive") } return nil } func validatePreparedIsolation( project ProjectRecord, work WorkRecord, target ExecutionTarget, prepared PreparedIsolation, ) (agentguard.AdmissionRequest, IsolationIdentity, error) { if prepared.Grant == nil || prepared.Descriptor == nil || prepared.Confinement == nil { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: isolation backend returned incomplete strict ports") } if project.Intent == nil { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: project has no manual start intent") } if prepared.Grant.ProjectID != string(project.ProjectID) || prepared.Grant.WorkspaceID != string(project.WorkspaceID) || prepared.Grant.Revision != string(project.Intent.GrantRevision) { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: workspace grant identity or revision mismatch") } if prepared.Descriptor.Mode != work.Unit.IsolationMode { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: isolation mode differs from the workflow request") } if prepared.Profile.ProviderID != target.ProviderID || prepared.Profile.ModelID != target.ModelID || prepared.Profile.ProfileID != target.ProfileID || prepared.Profile.Revision != target.ProfileRevision { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: admitted provider profile differs from selected target") } expectedConfinement := ConfinementBinding{ Revision: prepared.Descriptor.ConfinementRevision, IsolationID: prepared.Descriptor.ID, IsolationRevision: prepared.Descriptor.Revision, PinnedBaseRevision: prepared.Descriptor.PinnedBaseRevision, ConfigRevision: string(project.Intent.ConfigRevision), GrantRevision: prepared.Grant.Revision, ProfileRevision: prepared.Profile.Revision, BaseRoot: prepared.Descriptor.BaseRoot, TaskRoot: prepared.Descriptor.TaskRoot, WorkingDir: prepared.Descriptor.WorkingDir, WritableRoots: append([]string(nil), prepared.Descriptor.WritableRoots...), } actualConfinement := prepared.Confinement.Binding() expectedConfinement.RuntimeRoot = actualConfinement.RuntimeRoot expectedConfinement.SnapshotRoot = actualConfinement.SnapshotRoot if prepared.Confinement.Revision() != expectedConfinement.Revision { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: confinement proof revision differs from the isolation descriptor") } if err := prepared.Confinement.Validate(expectedConfinement); err != nil { return agentguard.AdmissionRequest{}, IsolationIdentity{}, fmt.Errorf("agenttask: invalid executable confinement proof: %w", err) } identity := IsolationIdentity{ ID: prepared.Descriptor.ID, Revision: prepared.Descriptor.Revision, Mode: prepared.Descriptor.Mode, PinnedBaseRevision: prepared.Descriptor.PinnedBaseRevision, TaskRoot: prepared.Descriptor.TaskRoot, } for field, value := range map[string]string{ "isolation": identity.ID, "isolation_revision": identity.Revision, "pinned_base_revision": identity.PinnedBaseRevision, } { if err := validateIdentity(field, value); err != nil { return agentguard.AdmissionRequest{}, IsolationIdentity{}, err } } return agentguard.AdmissionRequest{ Grant: prepared.Grant, Isolation: prepared.Descriptor, Profile: prepared.Profile, }, identity, nil } func validateSubmission(project ProjectRecord, work WorkRecord, submission Submission) error { if submission.ProjectID != project.ProjectID || submission.WorkUnitID != work.Unit.ID || submission.AttemptID != work.AttemptID { return fmt.Errorf("agenttask: submission durable identity mismatch") } if err := validateIdentity("artifact", string(submission.ArtifactID)); err != nil { return err } seen := make(map[LocatorKind]struct{}, len(submission.Locators)) for _, locator := range submission.Locators { if locator.Kind != LocatorProcess && locator.Kind != LocatorSession { return fmt.Errorf("agenttask: provider returned unsupported %q submission locator", locator.Kind) } if _, duplicate := seen[locator.Kind]; duplicate { return fmt.Errorf("agenttask: provider returned duplicate %q submission locator", locator.Kind) } seen[locator.Kind] = struct{}{} if err := validateLocator(project, work, locator); err != nil { return err } if existing, ok := work.Locators[locator.Kind]; ok && !reflect.DeepEqual(existing, locator) { return fmt.Errorf("agenttask: submission replaced the durable %q locator", locator.Kind) } } return nil } func (m *Manager) loadWork( ctx context.Context, projectID ProjectID, workID WorkUnitID, ) (ProjectRecord, WorkRecord, error) { state, err := m.load(ctx) if err != nil { return ProjectRecord{}, WorkRecord{}, err } project, ok := state.Projects[projectID] if !ok { return ProjectRecord{}, WorkRecord{}, fmt.Errorf("agenttask: project %q disappeared", projectID) } work, ok := project.Works[workID] if !ok { return ProjectRecord{}, WorkRecord{}, fmt.Errorf("agenttask: work %q disappeared", workID) } return project, work, nil } func (m *Manager) changeWork( ctx context.Context, projectID ProjectID, workID WorkUnitID, change func(*WorkRecord) error, ) error { return m.mutate(ctx, func(state *ManagerState) error { project, ok := state.Projects[projectID] if !ok { return fmt.Errorf("agenttask: project %q disappeared", projectID) } work, ok := project.Works[workID] if !ok { return fmt.Errorf("agenttask: work %q disappeared", workID) } if err := change(&work); err != nil { return err } work.UpdatedAt = m.clock.Now() project.Works[workID] = work project.UpdatedAt = m.clock.Now() state.Projects[projectID] = project return nil }) } func (m *Manager) blockWork( ctx context.Context, projectID ProjectID, workID WorkUnitID, state WorkState, blocker Blocker, ) { _ = m.changeWork(ctx, projectID, workID, func(work *WorkRecord) error { stage := failureStageForState(work.State) blocker = m.recordFailure(work, stage, blocker) if CanTransition(work.State, state) { work.State = state } else { work.State = WorkStateBlocked } work.Blocker = &blocker return nil }) m.emit(ctx, Event{ Type: EventBlocked, ProjectID: projectID, WorkUnitID: workID, State: state, Detail: string(blocker.Code), }) }