package agenttask import ( "context" "errors" "io" "os/exec" "time" "iop/packages/go/agentconfig" "iop/packages/go/agentguard" "iop/packages/go/agentpolicy" ) var ErrRevisionConflict = errors.New("agenttask state revision conflict") var ErrDeviceLeaseHeld = errors.New("agenttask device singleton lease is held by another owner") var ErrLeaseLost = errors.New("agenttask lease ownership lost during operation") // AgentTaskManager is the host-neutral lifecycle contract. StartProject records // a durable manual intent; only Reconcile may advance workflow state. type AgentTaskManager interface { StartProject(context.Context, StartRequest) error Reconcile(context.Context) error StopProject(context.Context, ProjectID) error } type Clock interface { Now() time.Time } type StateStore interface { Load(context.Context) (ManagerState, StateRevision, error) CompareAndSwap( context.Context, StateRevision, ManagerState, ) (StateRevision, error) } // WorkflowAdapter normalizes project-owned task artifacts. Listing projects is // separate from loading snapshots so one corrupt project cannot stop siblings. type WorkflowAdapter interface { RegisteredProjects(context.Context) ([]ProjectID, error) Snapshot(context.Context, ProjectID) (ProjectWorkflowSnapshot, error) } // ArtifactIdentity identifies one project-owned active plan/review artifact // without making the common manager parse project filesystem conventions. type ArtifactIdentity struct { ProjectID ProjectID WorkspaceID WorkspaceID WorkUnitID WorkUnitID AttemptID AttemptID ArtifactID ArtifactID } type ArtifactCompleteness string const ( ArtifactComplete ArtifactCompleteness = "complete" ArtifactPlaceholder ArtifactCompleteness = "placeholder" ) // ArtifactEvidence is the project adapter's normalized observation of the // active artifact pair. The adapter owns filesystem parsing; the manager owns // matching the observation against the durable submission identity. type ArtifactEvidence struct { Active bool Identity ArtifactIdentity Completeness ArtifactCompleteness RepairIntent *EvidenceRepairIntent } type WorkflowEvidenceStatus string const ( WorkflowEvidenceMatched WorkflowEvidenceStatus = "matched" WorkflowEvidenceNotActive WorkflowEvidenceStatus = "not_active" WorkflowEvidencePlaceholder WorkflowEvidenceStatus = "placeholder" WorkflowEvidenceIdentityMismatch WorkflowEvidenceStatus = "identity_mismatch" WorkflowEvidenceInvalid WorkflowEvidenceStatus = "invalid" ) type WorkflowEvidenceRequest struct { Project ProjectRecord Work WorkRecord Submission Submission } // EvidenceRepairIntent is valid only for a placeholder from Pi. It carries // the exact persisted session locator and dispatch ordinal so repair cannot // attach to a newer attempt or a different native conversation. type EvidenceRepairIntent struct { Identity ArtifactIdentity NativeLocator LocatorRecord DispatchOrdinal DispatchOrdinal } type WorkflowEvidenceRepairRequest struct { Project ProjectRecord Work WorkRecord Submission Submission Intent EvidenceRepairIntent } // WorkflowEvidence is a strict project workflow port. Observe must be // side-effect free; Repair may change only Pi worker-owned fields in the // native context identified by EvidenceRepairIntent. type WorkflowEvidence interface { Observe(context.Context, WorkflowEvidenceRequest) (ArtifactEvidence, error) Repair(context.Context, WorkflowEvidenceRepairRequest) error } type SelectionRequest struct { Project ProjectRecord Work WorkRecord } type Selector interface { Select(context.Context, SelectionRequest) (ExecutionTarget, error) } // PolicySelector evaluates the effective project policy identified by // SelectionContext.ProjectID against an immutable runtime config snapshot, // returning a durable RouteDecision. The agentpolicy.Evaluator implements this // interface. type PolicySelector interface { SelectPolicy( context.Context, agentconfig.RuntimeSnapshot, agentpolicy.SelectionContext, ) (agentpolicy.RouteDecision, error) } // FailureContinuationPolicyRequest identifies the immutable project/work // policy source for one failed attempt. The source does not receive or return a // final continuation decision. type FailureContinuationPolicyRequest struct { Project ProjectRecord Work WorkRecord CurrentTarget ExecutionTarget Observation agentpolicy.AttemptObservation } // FailureContinuationCandidate binds an exact host execution target to the // ordered eligibility and quota evidence supplied by immutable policy. type FailureContinuationCandidate struct { Target ExecutionTarget Eligible bool Quota agentpolicy.QuotaObservation } // FailureContinuationPolicy contains only declared policy inputs. Manager // combines these values with its current target, durable attempted-target // history, normalized observation, and authoritative failure budget before it // invokes agentpolicy.DecideContinuation. type FailureContinuationPolicy struct { Policy agentpolicy.FailurePolicy Candidates []FailureContinuationCandidate } // FailureContinuationPolicySource is an optional extension of Selector. It // cannot authorize a fabricated action or target because it returns only // immutable policy and ordered candidate inputs. type FailureContinuationPolicySource interface { Selector ContinuationPolicy( context.Context, FailureContinuationPolicyRequest, ) (FailureContinuationPolicy, error) } // FailureObservedInvocation exposes an already-normalized, safe observation // for a failed provider invocation. It contains no provider output or mutable // diagnostic maps and is the only observation Manager persists. type FailureObservedInvocation interface { ProviderInvocation FailureObservation() agentpolicy.AttemptObservation } type IsolationRequest struct { Project ProjectRecord Work WorkRecord Target ExecutionTarget IdempotencyKey string } type PreparedIsolation struct { Grant *agentguard.WorkspaceGrant Descriptor *agentguard.IsolationDescriptor Profile agentguard.ProviderProfile Confinement InvocationConfinement } type IsolationBackend interface { Prepare(context.Context, IsolationRequest) (PreparedIsolation, error) } // ConfinementBinding is the immutable identity that an executable filesystem // confinement proof must cover. RuntimeRoot and SnapshotRoot identify the // protected device-local tree; only WritableRoots may be mutated by the child. type ConfinementBinding struct { Revision string IsolationID string IsolationRevision string PinnedBaseRevision string ConfigRevision string GrantRevision string ProfileRevision string BaseRoot string RuntimeRoot string SnapshotRoot string TaskRoot string WorkingDir string WritableRoots []string } // ConfinementCommand contains only non-I/O launch data. InvocationConfinement // owns child stdio creation so callers cannot pass a pre-opened descriptor // through the executable confinement boundary. type ConfinementCommand struct { Name string Args []string Env []string } // StartedConfinement is the exact child and parent-side pipe set created by a // validated executable confinement proof. BindStarted assumes ownership after // a successful bind. Before that transfer, Abort closes every pipe endpoint, // terminates the child, and reaps it. type StartedConfinement interface { Child() *exec.Cmd Stdin() io.WriteCloser Stdout() io.ReadCloser Stderr() io.ReadCloser Abort() error } // InvocationConfinement is an executable, identity-bound child launcher. // Isolation backends issue proofs; provider invokers consume the exact proof // carried by DispatchRequest rather than asserting a capability boolean. type InvocationConfinement interface { Revision() string Binding() ConfinementBinding Validate(ConfinementBinding) error Start(context.Context, ConfinementCommand) (StartedConfinement, error) } type DispatchRequest struct { Project ProjectRecord Work WorkRecord Target ExecutionTarget AdmissionRequest agentguard.AdmissionRequest Permit *agentguard.Permit Workspace agentguard.CanonicalWorkspace Confinement InvocationConfinement IdempotencyKey string } type ProviderInvocation interface { Locators() []LocatorRecord Wait(context.Context) (Submission, error) Cancel(context.Context) error } // ProviderLaunch is a side-effect-free provider launch plan. The manager owns // the only process start: it passes Command to the validated confinement proof // and then binds the exact returned child and proof-owned pipes to a durable // invocation handle. type ProviderLaunch interface { Command() ConfinementCommand BindStarted(StartedConfinement) (ProviderInvocation, error) } type ProviderInvoker interface { // Prepare must not start a process, session, or other provider side effect. // Manager invokes the returned command through InvocationConfinement.Start. Prepare(context.Context, DispatchRequest) (ProviderLaunch, error) } type RecoveryExecutionState string const ( RecoveryExecutionAbsent RecoveryExecutionState = "absent" RecoveryExecutionLive RecoveryExecutionState = "live" RecoveryExecutionSubmitted RecoveryExecutionState = "submitted" RecoveryExecutionExited RecoveryExecutionState = "exited" RecoveryExecutionAmbiguous RecoveryExecutionState = "ambiguous" ) type RecoveryCompletionState string const ( RecoveryCompletionUnknown RecoveryCompletionState = "unknown" RecoveryCompletionComplete RecoveryCompletionState = "complete" RecoveryCompletionPartial RecoveryCompletionState = "partial" RecoveryCompletionAmbiguous RecoveryCompletionState = "ambiguous" ) type RecoveryRequest struct { Project ProjectRecord Work WorkRecord Locators map[LocatorKind]LocatorRecord } // RecoveryObservation is identity-bound so stale process, session, overlay, or // archive evidence cannot be rebound to a current attempt. type RecoveryObservation struct { ProjectID ProjectID WorkspaceID WorkspaceID WorkUnitID WorkUnitID AttemptID AttemptID Execution RecoveryExecutionState Completion RecoveryCompletionState Submission *Submission } type RecoveryInspector interface { Inspect(context.Context, RecoveryRequest) (RecoveryObservation, error) } type ReviewRequest struct { Project ProjectRecord Work WorkRecord Submission Submission IdempotencyKey string } type Reviewer interface { Review(context.Context, ReviewRequest) (ReviewResult, error) } type IntegrationRequest struct { Project ProjectRecord Work WorkRecord ChangeSet ChangeSetIdentity Ordinal DispatchOrdinal Attempt IntegrationAttempt IdempotencyKey string } type Integrator interface { Integrate(context.Context, IntegrationRequest) (IntegrationResult, error) } type EventSink interface { Emit(context.Context, Event) error } type nopEventSink struct{} func (nopEventSink) Emit(context.Context, Event) error { return nil } type systemClock struct{} func (systemClock) Now() time.Time { return time.Now().UTC() }