// Package supervisor defines the narrow process-control seam shared by the // client runtime and platform implementations. It intentionally contains no // operating-system handles or process APIs. package supervisor import ( "context" "errors" "time" rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1" "github.com/rvbox/rvbox/internal/domain" ) var ( ErrInvalidStartSpec = errors.New("invalid supervisor start specification") ErrUnsupported = errors.New("supervisor operation is unsupported") ) type SignalKind uint8 const ( SignalTerm SignalKind = iota + 1 SignalKill ) // StartSpec is already validated at the protocol boundary. The supervisor // still checks the identity/revision/source invariants because it is a second // durability boundary and may be called after a restart. type StartSpec struct { IssueUUID domain.UUID CommandRevision uint64 Execution *rvboxv1.ExecutionSpec // ScriptBody is the verified, durable body for Execution.script. It is // supplied by the client spool only after the declared digest/length have // been checked; command_text requests leave it empty. ScriptBody []byte WorkingDirectory string Environment map[string]string ExecutionProfiles []string } func (spec StartSpec) Validate() error { if _, err := domain.ParseUUIDv7(spec.IssueUUID.String()); err != nil || spec.CommandRevision == 0 || spec.Execution == nil || spec.Execution.Source == nil { return ErrInvalidStartSpec } if spec.WorkingDirectory == "" { return ErrInvalidStartSpec } return nil } // EffectiveIdentity is immutable process evidence captured before launch. // Empty user/session fields mean a Session 0 service context. type EffectiveIdentity struct { Context string SessionID uint32 UserSID string LogonSID string Elevated bool Integrity string } type Process interface { IssueUUID() domain.UUID Identity() EffectiveIdentity // ReadOutput returns the next bounded stdout/stderr chunk. It continues // until both child pipes reach EOF, so Wait never reports a terminal // result before the captured output has drained. ReadOutput(context.Context) (OutputChunk, error) Wait(context.Context) (ExitStatus, error) WriteStdin(context.Context, []byte, bool) error CloseStdin(context.Context) error } // OutputChunk is intentionally raw. Compression, quota admission, local // ordering, and wire sequencing belong to the client spool rather than the // operating-system supervisor. type OutputChunk struct { Stream rvboxv1.StreamKind Data []byte } type ExitStatus struct { Code int32 Signaled bool Signal SignalKind StartedAt time.Time FinishedAt time.Time OutputDrained bool Output bool } type SignalOutcome struct { Delivered bool Escalated bool Detail string ObservedAt time.Time } type ResourceSnapshot struct { CPUTime time.Duration ResidentBytes uint64 IOReadBytes uint64 IOWriteBytes uint64 ProcessCount uint64 ObservedAt time.Time Complete bool Detail string } type Supervisor interface { Start(context.Context, StartSpec) (Process, error) Signal(context.Context, Process, SignalKind) (SignalOutcome, error) Snapshot(context.Context, Process) (ResourceSnapshot, error) StopAll(context.Context) error }