control

package
v0.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package control defines Rainier's public control-plane application contract: the portable domain vocabulary, the caller-facing application interfaces, and the narrow host-supplied ports that self-hosted controld and Rainier Cloud both consume. Its canonical import path is github.com/tokencanopy/rainier/control.

The package is a contract, not a service. It contains no implementation of the lifecycle, scheduling, reconciliation, or attach behavior: it freezes the seam those behaviors will be extracted behind, and pins it with external-package contract tests so the behaviors can be moved out of internal/controld by later workers without editing this surface.

The package is neutral in four ways, each a hard boundary:

  • Transport-neutral: it defines no HTTP handler, WebSocket route, SQL statement, or wire frame. Adapters map these sentinels and commands to a concrete transport.
  • Identity-neutral: it carries no role, email, GitHub account, or membership record. Actors are opaque IDs produced by a host adapter, never decoded from client JSON.
  • Persistence-neutral: repository ports expose only the semantic reads and transitions the existing application behavior needs. They never expose SQL transactions, rows, JSON blobs, credentials, secrets, user records, or provider resources.
  • Provider-neutral: no GCP project, AWS account, Azure subscription, machine type, cluster, native zone, or disk ID appears anywhere in the package. Placement is expressed in Rainier execution modes, product regions, portable capabilities, and opaque pool and runner identities.

Terminal and workspace bytes remain the already-public protocol packages (github.com/tokencanopy/rainier/protocol/{terminal,runner,workspace}). This package references those contracts but never duplicates their message structs.

Compatibility

This surface is pre-v1 and may evolve during /v0/, but there is one canonical contract at a time: no V2, Legacy, compatibility-alias, or Cloud-fork type exists here. Later workers may consume this package but must not edit its exported signatures; a change to the contract is a coordinated decision, not a per-lane convenience.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalid reports a command or scope that is malformed: an empty or
	// unknown ID, an unknown actor kind or execution mode, a scope missing
	// its hosted region or cell, or a contradictory create (an environment
	// and a scratch spec together). It is the one non-disclosing answer for
	// input that cannot be authorized against anything.
	ErrInvalid = errors.New("control: invalid")

	// ErrDenied reports that the current authorizer refused the operation.
	// The resource may or may not exist; ErrDenied does not say which.
	ErrDenied = errors.New("control: denied")

	// ErrNotFound reports a lookup that found nothing. It is also the
	// non-disclosing answer for a resource outside the authoritative
	// workspace: a caller asking about another workspace's session learns
	// "not found", never "that workspace exists and has this session".
	ErrNotFound = errors.New("control: not found")

	// ErrConflict reports a guarded transition whose current state was not in
	// the allowed from-list, a name already held, or a contradictory request.
	ErrConflict = errors.New("control: conflict")

	// ErrStale reports an operation whose authoritative generation or setup
	// hash no longer matches the resource's current one: a runner event from
	// a superseded placement generation, or a snapshot built from an edited
	// environment.
	ErrStale = errors.New("control: stale")

	// ErrUnavailable reports a dependency that is temporarily unusable: a
	// runner with no control connection, a store that cannot answer.
	ErrUnavailable = errors.New("control: unavailable")

	// ErrUnsupported reports an operation or capability the current build
	// does not implement.
	ErrUnsupported = errors.New("control: unsupported")
)

The closed error set of the control contract. Every operation in this package reports failure through one of these seven sentinels; ports may wrap a sentinel with safe context but must not surface SQL, credentials, provider responses, filesystem paths, terminal output, or session content in that context. Callers branch with errors.Is and never inspect the wrapped message text.

HTTP adapters map these centrally to status codes; this package carries no status code and no public error-envelope text.

NonTerminal lists every non-terminal state, in the order a session normally progresses through them. Callers pass it as the from-list of a guarded transition when any live state should be accepted.

Functions

This section is empty.

Types

type Action

type Action string

Action is the closed action vocabulary of the frozen application operations. The action and the resource kind together name an operation the Authorizer may allow or deny.

const (
	ActionCreate   Action = "create"
	ActionGet      Action = "get"
	ActionList     Action = "list"
	ActionUpdate   Action = "update"
	ActionDelete   Action = "delete"
	ActionSuspend  Action = "suspend"
	ActionResume   Action = "resume"
	ActionSnapshot Action = "snapshot"
	ActionAttach   Action = "attach"
	ActionDiff     Action = "diff"
	ActionPush     Action = "push"
	ActionPull     Action = "pull"
)

type Actor

type Actor struct {
	ID   ActorID
	Kind ActorKind
}

Actor is an authenticated principal. It is deliberately identity-only: it carries no role, email, or membership record, and no cached allow/deny decision. Current authorization is always an Authorizer call against the surrounding Scope.

type ActorID

type ActorID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

type ActorKind

type ActorKind string

ActorKind names the two kinds of principal an operation may run as. An actor is authoritative adapter output: the host constructs it from authenticated state, never by decoding a client-supplied field from JSON.

const (
	// ActorUser is a human operator acting on their own behalf.
	ActorUser ActorKind = "user"
	// ActorService is a narrowly scoped principal acting for background work
	// or runner events, not a user.
	ActorService ActorKind = "service"
)

type Application

type Application interface {
	Sessions
	Environments
	Fleet
	Attachments
}

Application is the whole caller-facing application contract. It embeds the four operation-oriented interfaces and nothing else, so a consumer depends on the behaviors it uses rather than on a concrete service type.

type AttachTarget

type AttachTarget struct {
	WorkspaceID          WorkspaceID
	SessionID            SessionID
	PoolID               PoolID
	RunnerID             RunnerID
	PlacementGeneration  uint64
	ControllerGeneration uint64
}

AttachTarget is the fully resolved binding an AttachmentBroker needs to splice a stream to a session: the workspace, session, pool, runner, and the placement and controller generations the application granted.

type AttachTerminal

type AttachTerminal struct {
	SessionID SessionID
	Since     uint64
	Mode      AttachmentMode
}

AttachTerminal is the command for AttachTerminal. Since is the attach cursor (terminal.SinceAll for the whole log, 0 for a snapshot of the current screen). Mode distinguishes viewer from controller intent.

type AttachmentBroker

type AttachmentBroker interface {
	Attach(ctx context.Context, target AttachTarget, stream TerminalStream) error
}

AttachmentBroker splices a terminal stream onto a session, given a fully resolved AttachTarget. The granted controller generation arrives out of band; the broker never changes terminal JSON.

type AttachmentMode

type AttachmentMode string

AttachmentMode names the intent of an attach: a viewer reads a session's terminal; a controller also writes to it. Controller authorization and the monotonic controller-lease generation are application facts — the AttachmentBroker receives the granted generation out of band rather than changing the terminal protocol.

const (
	AttachmentViewer     AttachmentMode = "viewer"
	AttachmentController AttachmentMode = "controller"
)

type Attachments

type Attachments interface {
	AttachTerminal(context.Context, Scope, AttachTerminal, TerminalStream) error
	WorkspaceDiff(context.Context, Scope, WorkspaceDiff) (workspace.DiffAnswer, error)
	PushWorkspace(context.Context, Scope, PushWorkspace) error
	PullWorkspace(context.Context, Scope, PullWorkspace) error
}

Attachments is the attach/workspace half of the caller-facing application contract. Terminal and workspace bytes use the public protocol packages; this interface references them and never duplicates their message structs.

type Authorizer

type Authorizer interface {
	Authorize(context.Context, Scope, Action, Resource) error
}

Authorizer is the current authorization authority. The application invokes it before any state disclosure or side effect; self-hosted and Cloud supply different policy adapters behind the same signature.

type Checkpoint

type Checkpoint struct {
	Ref          string
	Format       string
	Capabilities []string
}

Checkpoint is a portable opaque reference to a session snapshot, plus its format and capability metadata. The provider object or image reference behind Ref stays inside the checkpoint adapter; this type never names it.

type CheckpointLocation

type CheckpointLocation struct {
	Portable bool
	Runners  []RunnerID
}

CheckpointLocation is where a checkpoint can be booted: on any runner of the pool (Portable), or only on the named ones. Both empty means nowhere — the checkpoint is not usable right now and the caller boots without it.

type CheckpointLocator

type CheckpointLocator interface {
	LocateCheckpoint(ctx context.Context, ws WorkspaceID, cp Checkpoint) (CheckpointLocation, error)
}

CheckpointLocator is the host's knowledge of where checkpoint artifacts live. Self-hosted snapshots are container images on the runner that built them; hosted checkpoints are regional objects any capable runner restores. The application asks and never assumes.

type Clock

type Clock interface {
	Now() time.Time
}

Clock supplies time to the application. Adapters may freeze or skew it in tests.

type Connector

type Connector struct {
	Type string
	Raw  json.RawMessage
}

Connector is one declared attachment of an environment, treated opaquely by the control model: Type is the connector kind, and Raw is the original object verbatim. Adapters bound and validate connector payloads (the control model does not know GitHub token storage, file paths, or tunnel targets).

type CreateEnvironment

type CreateEnvironment struct {
	Name            string
	Image           string
	Setup           string
	Init            string
	InitTimeoutSec  int
	EgressAllow     []string
	SecretRefs      []string
	Connectors      []Connector
	Requirements    Requirements
	SetupTimeoutSec int
}

CreateEnvironment is the command for CreateEnvironment.

type CreateSession

type CreateSession struct {
	Name           string
	EnvironmentID  EnvironmentID
	Spec           PortableSpec
	Repos          []RepoRef
	IdempotencyKey string
}

CreateSession is the command for CreateSession. EnvironmentID names the environment the session starts from, or is empty for a scratch session; Spec is the session's own execution description, layered over that environment by the rules on PortableSpec. No combination of the two is contradictory: a session that names an environment may still choose its command, override its image, or reach more hosts, and a scratch session that names no image asks the host for its default one. A host that wants to forbid an override, or require an image, does so in its own policy — this contract says what is possible, not what a given host allows.

Repos overrides the repositories the environment's connectors declare. Its nil-vs-empty distinction is load-bearing: nil means "the caller said nothing, inherit the environment's connectors"; a non-nil empty slice means "clone nothing"; a non-empty slice means "clone exactly these, in order".

It does not accept CPU, memory, a VM shape, or a user-selected size: environment defaults and host policy derive Requirements, so an ordinary session is created without any sizing choice.

func (CreateSession) Validate

func (c CreateSession) Validate() error

Validate reports whether c is well formed. It returns ErrInvalid for a repository reference that names no repository. No combination of EnvironmentID and Spec is refused, because none is contradictory (see PortableSpec).

type DeleteEnvironment

type DeleteEnvironment struct {
	ID EnvironmentID
}

DeleteEnvironment is the command for DeleteEnvironment.

type DeleteSession

type DeleteSession struct {
	ID SessionID
}

DeleteSession is the command for DeleteSession.

type Environment

type Environment struct {
	ID              EnvironmentID
	WorkspaceID     WorkspaceID
	Name            string
	Image           string
	Setup           string
	SetupHash       string // identity of the build inputs (image + setup)
	Init            string // per-boot hook, run after setup and clone
	InitTimeoutSec  int
	EgressAllow     []string
	SecretRefs      []string // secret names; the control model never carries a value
	Connectors      []Connector
	Requirements    Requirements
	SetupTimeoutSec int
	// Snapshot is the cached checkpoint built from this environment's setup,
	// if one exists. SnapshotHash records which SetupHash it was built from;
	// a snapshot whose hash no longer matches the environment's is stale.
	Snapshot     Checkpoint
	SnapshotHash string
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

Environment is a named, reusable template a session starts from, as the application service sees it: image, setup and init scripts, egress hosts, secret references (names only, never values), connectors, portable requirements, checkpoint metadata, and timestamps. It names no provider, machine shape, or size.

type EnvironmentID

type EnvironmentID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

type EnvironmentPage

type EnvironmentPage struct {
	Environments []Environment
	NextCursor   string
}

EnvironmentPage is one page of ListEnvironments. NextCursor is empty on the last page.

type EnvironmentQuery

type EnvironmentQuery struct {
	Limit  int
	Cursor string
}

EnvironmentQuery filters and paginates ListEnvironments. Limit is capped by the implementation, Cursor is opaque, and rows come back in stable (name, id) order.

type EnvironmentRepository

type EnvironmentRepository interface {
	CreateEnvironment(ctx context.Context, ws WorkspaceID, e Environment) (Environment, error)
	GetEnvironment(ctx context.Context, ws WorkspaceID, id EnvironmentID) (Environment, error)
	ListEnvironments(ctx context.Context, ws WorkspaceID, q EnvironmentQuery) ([]Environment, string, error)
	UpdateEnvironment(ctx context.Context, ws WorkspaceID, e Environment) (Environment, error)
	DeleteEnvironment(ctx context.Context, ws WorkspaceID, id EnvironmentID) error
	// CountSessionsByEnvironment counts sessions on envID whose state is in
	// states; an empty states counts every session on the environment.
	CountSessionsByEnvironment(ctx context.Context, ws WorkspaceID, envID EnvironmentID, states []SessionState) (int, error)
	// SetEnvironmentSnapshot records a built snapshot against the environment
	// only while its SetupHash still equals expectHash; otherwise it changes
	// nothing and reports a stale/conflict outcome. ErrStale when SetupHash no
	// longer equals expectHash, ErrNotFound when envID does not exist in ws.
	SetEnvironmentSnapshot(ctx context.Context, ws WorkspaceID, envID EnvironmentID, expectHash, ref string, runnerID RunnerID) error
}

EnvironmentRepository is the workspace-keyed environment persistence port, mapped from internal/controld.Store:

CreateEnvironment        → Store.CreateEnvironment
GetEnvironment           → Store.GetEnvironment
ListEnvironments         → Store.ListEnvironments
UpdateEnvironment        → Store.UpdateEnvironment
DeleteEnvironment        → Store.DeleteEnvironment
CountSessionsByEnvironment → Store.CountSessionsByEnvironment
SetEnvironmentSnapshot   → Store.SetEnvironmentSnapshot

type Environments

type Environments interface {
	CreateEnvironment(context.Context, Scope, CreateEnvironment) (Environment, error)
	GetEnvironment(context.Context, Scope, EnvironmentID) (Environment, error)
	ListEnvironments(context.Context, Scope, EnvironmentQuery) (EnvironmentPage, error)
	UpdateEnvironment(context.Context, Scope, UpdateEnvironment) (Environment, error)
	DeleteEnvironment(context.Context, Scope, DeleteEnvironment) error
}

Environments is the environment half of the caller-facing application contract.

type Event

type Event struct {
	ID          EventID
	WorkspaceID WorkspaceID
	ActorID     ActorID
	Action      Action
	Resource    Resource
	At          time.Time
	Usage       Usage
	// PlacementGeneration is the session placement generation an event about
	// a session happened under, so usage is attributed to exactly one
	// generation; zero for an event about any other resource.
	PlacementGeneration uint64
}

Event is a fixed-field, provider-neutral application fact: its own stable event ID, the workspace and actor it happened for, the resource it touched and the action taken, the timestamp, and optional usage facts. It has no terminal data, conversation content, secret, raw error, price, or provider resource ID.

type EventID

type EventID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

type EventRecorder

type EventRecorder interface {
	Record(context.Context, Event) error
}

EventRecorder records one application event. It is deliberately a semantic port: the later persistence/outbox plan makes mutation plus event atomic without changing the event vocabulary.

type ExecutionMode

type ExecutionMode string

ExecutionMode names the three Rainier execution products. It is a Rainier concept, not a provider one: dedicated and serverless both hide their provider underneath, and self_hosted names an installation the customer runs from the OSS repository.

const (
	// ExecutionSelfHosted is a customer-operated installation.
	ExecutionSelfHosted ExecutionMode = "self_hosted"
	// ExecutionDedicated is a Rainier-managed workspace-exclusive execution
	// plane.
	ExecutionDedicated ExecutionMode = "dedicated"
	// ExecutionServerless is Rainier-managed shared capacity with a hardened
	// sandbox per session.
	ExecutionServerless ExecutionMode = "serverless"
)

type Fleet

type Fleet interface {
	RegisterRunner(context.Context, RunnerRegistration) (RunnerRegistrationResult, error)
	ReconcileRunner(context.Context, RunnerSnapshot) (ReconcileResult, error)
	ApplyRunnerEvent(context.Context, RunnerEvent) error
	ListRunners(context.Context, Scope, RunnerQuery) (RunnerPage, error)
}

Fleet is the fleet half of the caller-facing application contract. The first three methods are service-principal calls: they carry authoritative bindings in their payload and never accept a user-created Scope. ListRunners is an ordinary scoped query.

type FleetRepository

type FleetRepository interface {
	// UpsertRunner stores r as pool's view of that runner. ErrStale when
	// r.Generation is below the runner's stored generation; nothing changes.
	UpsertRunner(ctx context.Context, pool PoolID, r Runner) error
	SetRunnerConnected(ctx context.Context, pool PoolID, id RunnerID, connected bool) error
	ListRunners(ctx context.Context, pool PoolID) ([]Runner, error)
	// SessionsOnRunner returns the sessions in states placed on id within pool.
	SessionsOnRunner(ctx context.Context, pool PoolID, id RunnerID, states []SessionState) ([]Session, error)
	// OldestQueued returns the queued sessions of pool, oldest first.
	OldestQueued(ctx context.Context, pool PoolID) ([]Session, error)
}

FleetRepository is the pool-keyed runner/capacity persistence port, mapped from internal/controld.Store:

UpsertRunner       → Store.UpsertRunner
SetRunnerConnected → Store.SetRunnerConnected
ListRunners        → Store.ListRunners
SessionsOnRunner   → Store.SessionsOnRunner (capacity math, reconciliation)
OldestQueued       → Store.OldestQueued (placement pass)

type IDGenerator

type IDGenerator interface {
	NewSessionID() SessionID
	NewEnvironmentID() EnvironmentID
	NewEventID() EventID
}

IDGenerator mints the three identities the application allocates. Adapters may prefix, namespace, or verify uniqueness; the application only requires that returned IDs are non-empty and distinct.

type PlacementScope

type PlacementScope struct {
	ProductRegion string
	HomeCell      string
	Mode          ExecutionMode
}

PlacementScope is the Rainier placement context of a call: which product region the workspace lives in, which cell is its home, and which execution mode it runs under. It is authoritative adapter output — the host derives it from current authoritative records, and the client cannot supply or override it.

For a self-hosted installation the region and cell are the documented installation-local values ("self-hosted" and "default" are typical), not a real cloud region.

type Pool

type Pool struct {
	ID            PoolID
	Capabilities  []string
	CapacityUsed  int
	CapacityTotal int
}

Pool is an opaque eligible scheduling boundary with aggregate capacity and capabilities. The pool resolver may change providers without changing a session request; the application selects among runners inside one pool.

type PoolID

type PoolID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

type PoolResolver

type PoolResolver interface {
	EligiblePools(context.Context, Scope, Requirements) ([]Pool, error)
}

PoolResolver owns product/provider policy: it returns the eligible pools for a session's requirements. The application owns selection among the eligible runners inside the chosen pool.

type PortableSpec

type PortableSpec struct {
	Image       string
	Cmd         []string
	EgressAllow []string
	Repos       []RepoRef
}

PortableSpec is the resolved, provider-neutral execution description of a session: what image to boot, what command to run, which egress hosts it may reach, and which repositories to clone. It names no VM shape, no size, and no provider resource.

On a CreateSession it is the session's own description, layered over the environment the create names, if any. An environment is a template and a session is an instance of it: every field that is set overrides the environment's, and every field that is unset is inherited. Unset is "" for Image and nil for a list; an explicitly empty list means "none".

Image        unset: the environment's image — its current snapshot when
             one is valid — or, on a scratch session, the host's default
             image. Set: this image, and no snapshot reuse for this
             session, because a snapshot is built from the environment's
             own image and setup.
Cmd          unset: the image's default command. Set: this command. An
             environment carries no command; this is how a session from
             one says what to run.
EgressAllow  unset: the environment's list. Set: the environment's list
             extended by these hosts, in order, without duplicates. An
             environment's egress is what it needs to work; a session
             adds to it and never silently removes from it.
Repos        the repository override; see CreateSession.Repos.

type PullWorkspace

type PullWorkspace struct {
	SessionID SessionID
	Path      string
	Body      io.Writer
}

PullWorkspace is the command for PullWorkspace: stream the gzipped tar archive of Path out of the session's workspace into Body.

type PushWorkspace

type PushWorkspace struct {
	SessionID SessionID
	Path      string
	Body      io.Reader
}

PushWorkspace is the command for PushWorkspace: stream the gzipped tar archive at Body into Path inside the session's workspace. Body is bounded by the public workspace limits; no second archive or path type is introduced.

type ReconcileResult

type ReconcileResult struct {
	// Generation is the generation now authoritative for this runner.
	Generation uint64
	// Fenced reports whether the snapshot lost to a newer generation and the
	// runner must stop acting on older authority.
	Fenced bool
	// Destroy names sessions the store has no live record of on this runner;
	// the runner must tear them down as orphans.
	Destroy []SessionID
}

ReconcileResult is the application's answer to a snapshot.

type RepoRef

type RepoRef struct {
	Repo       string
	BaseBranch string
}

RepoRef is one entry of a session's repository override, in the spelling the caller sent: "owner/name" plus the branch to clone from. It is the request shape, not the resolved clone instruction (that lives in the public runner protocol). An empty BaseBranch means the default branch.

type Requirements

type Requirements struct {
	Capabilities   []string // portable runtime capabilities, e.g. "gpu"
	MinCPU         int64    // whole vCPU units; 0 = unspecified
	MinMemoryBytes int64    // 0 = unspecified
	MinDiskBytes   int64    // 0 = unspecified
}

Requirements is the portable capability-and-resource ask a session (or its environment) makes of the pool that will run it. It names portable capabilities and resource minima; it has no provider SKU, machine type, or user-selected size. Session sizing stays optional and automatic for clients — environment defaults and host policy derive Requirements.

type Resource

type Resource struct {
	Kind        ResourceKind
	WorkspaceID WorkspaceID
	ID          string // the resource's opaque identifier
	CreatorID   ActorID
}

Resource names the resource an authorization decision is about: its kind, its authoritative workspace, its opaque ID, and its creator when the resource has one. It carries no role — roles are the adapter's to interpret, never a field here.

type ResourceKind

type ResourceKind string

ResourceKind is the closed resource-kind vocabulary of the frozen application operations.

const (
	ResourceSession     ResourceKind = "session"
	ResourceEnvironment ResourceKind = "environment"
	ResourceRunner      ResourceKind = "runner"
)

type ResumeSession

type ResumeSession struct {
	ID SessionID
}

ResumeSession is the command for ResumeSession.

type Runner

type Runner struct {
	ID            RunnerID
	PoolID        PoolID
	CapacityUsed  int
	CapacityTotal int
	Connected     bool
	// Generation is monotonic per runner; a stale holder is rejected without
	// replacing the event shapes (see RunnerEvent).
	Generation   uint64
	Capabilities []string
	LastSeenAt   time.Time
}

Runner is a registered fleet member within a pool and its current capacity. Identity and generation are opaque Rainier identities; provider identity stays in adapters.

type RunnerEvent

type RunnerEvent struct {
	WorkspaceID   WorkspaceID
	PoolID        PoolID
	RunnerID      RunnerID
	Generation    uint64
	SessionID     SessionID
	State         SessionState
	Detail        string
	ChildExitCode *int
	// PlacementGeneration is the session placement generation the runner
	// was given when the sandbox was created, echoed back so a report from a
	// stale sandbox is fenced by the session's own authority and not only by
	// the connection it arrived on. Zero means "not carried" (an old runner)
	// and fences nothing.
	PlacementGeneration uint64
}

RunnerEvent is one unsolicited lifecycle report a runner makes about a session it holds. It carries its own authoritative workspace, pool, runner, and generation bindings; an event that does not match the authoritative workspace, pool, runner, or generation is stale and ignored. State is the lifecycle state the event reports; Detail is the runner's own sentence (failure tail, snapshot ref); ChildExitCode is set for a child exit.

type RunnerID

type RunnerID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

type RunnerPage

type RunnerPage struct {
	Runners    []Runner
	NextCursor string
}

RunnerPage is one page of ListRunners. NextCursor is empty on the last page.

type RunnerQuery

type RunnerQuery struct {
	Limit  int
	Cursor string
}

RunnerQuery filters and paginates ListRunners. Limit is capped by the implementation, Cursor is opaque, and rows come back in stable (id) order.

type RunnerRegistration

type RunnerRegistration struct {
	WorkspaceID   WorkspaceID
	PoolID        PoolID
	RunnerID      RunnerID
	Generation    uint64
	CapacityUsed  int
	CapacityTotal int
	Capabilities  []string
	Sessions      []RunnerSession
}

RunnerRegistration is a runner's registration claim. Fleet service-principal calls carry their authoritative workspace, pool, runner, and session bindings here rather than accepting a user-created Scope. Every field is adapter-derived; none is decoded directly from client JSON.

type RunnerRegistrationResult

type RunnerRegistrationResult struct {
	// Accepted reports whether the registration took effect. A stale
	// generation is refused rather than recorded.
	Accepted bool
	// Generation is the generation now authoritative for this runner.
	Generation uint64
}

RunnerRegistrationResult is the application's answer to a registration.

type RunnerSession

type RunnerSession struct {
	SessionID SessionID
	State     SessionState
}

RunnerSession is one session a runner reports it holds, for registration and reconciliation.

type RunnerSnapshot

type RunnerSnapshot struct {
	WorkspaceID   WorkspaceID
	PoolID        PoolID
	RunnerID      RunnerID
	Generation    uint64
	CapacityUsed  int
	CapacityTotal int
	Sessions      []RunnerSession
}

RunnerSnapshot is a runner's authoritative current-state report for reconciliation: its identity, generation, capacity, and the sessions it holds.

type RunnerTransport

type RunnerTransport interface {
	Dispatch(ctx context.Context, pool PoolID, id RunnerID, m runner.ToRunner) (runner.FromRunner, error)
	Connected(pool PoolID, id RunnerID) bool
}

RunnerTransport dispatches commands to a runner and reports connectivity. Dispatch carries the public runner protocol as-is; transport authentication and connection ownership stay in adapters.

type Scope

type Scope struct {
	WorkspaceID WorkspaceID
	Actor       Actor
	Placement   PlacementScope
}

Scope is the authoritative context every hosted application command and query receives. It carries the workspace and actor the call is authorized as, plus the placement context. It contains no role and no cached allow/deny decision: the Authorizer is the current authority, invoked against this scope before any state disclosure or side effect.

func (Scope) Validate

func (s Scope) Validate() error

Validate reports whether s is a usable scope. A zero Scope is invalid; so is one with an empty workspace or actor ID, an unknown actor kind, an unknown execution mode, or a missing product region or home cell. It returns ErrInvalid for every rejection, and never a free-form message.

type Session

type Session struct {
	ID            SessionID
	WorkspaceID   WorkspaceID
	CreatorID     ActorID
	Name          string
	State         SessionState
	EnvironmentID EnvironmentID // "" for a scratch session
	Spec          PortableSpec  // the resolved execution description
	SetupHash     string        // identity of the setup script actually dispatched; "" when none
	PoolID        PoolID
	RunnerID      RunnerID
	// PlacementGeneration is the monotonic generation of this session's
	// current placement. Later hosted fencing rejects a runner event whose
	// generation does not match, without replacing the event shape. A
	// repository advances it by one on every Transition whose RunnerID option
	// names a runner, and leaves it unchanged otherwise. A generation is one
	// sandbox on one runner: the scheduler's placement, reconcile's adoption,
	// and a cold resume — which names the row's own runner, because it starts
	// a new sandbox there — each open one; a warm resume unpauses the sandbox
	// it has and opens none.
	PlacementGeneration uint64
	// ControllerGeneration is the monotonic generation of this session's
	// current terminal controller: 0 until a controller has attached, then
	// the value NextControllerGeneration last returned. A viewer attaches
	// under the current value; a controller advances it. Stale input is
	// fenced against it by the attachment plane.
	ControllerGeneration uint64
	IdempotencyKey       string
	ChildExitCode        *int
	Error                string
	CreatedAt            time.Time
	UpdatedAt            time.Time
	LastEventAt          time.Time
}

Session is one coding-agent run as the application service sees it: its identity, workspace, creator, lifecycle state, resolved portable execution spec, selected pool and runner, monotonic placement generation, idempotency key, exit code, and timestamps. It carries no role, email, provider, native machine shape, charge, or credential.

type SessionID

type SessionID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

type SessionPage

type SessionPage struct {
	Sessions   []Session
	NextCursor string
}

SessionPage is one page of ListSessions. NextCursor is empty on the last page.

type SessionQuery

type SessionQuery struct {
	IncludeTerminal bool
	Limit           int
	Cursor          string
}

SessionQuery filters and paginates ListSessions. Limit is capped by the implementation; Cursor is opaque to callers; rows come back in stable (created_at, id) order; and IncludeTerminal admits the terminal states that the default list hides. There is no provider filter: a query cannot name a provider, machine type, zone, or native resource.

type SessionRepository

type SessionRepository interface {
	// CreateSession stores s and returns the stored row. ErrConflict when the
	// name is already held by another non-terminal session of the same
	// creator; a replayed idempotency key returns the existing row.
	CreateSession(ctx context.Context, ws WorkspaceID, s Session) (Session, error)
	GetSession(ctx context.Context, ws WorkspaceID, id SessionID) (Session, error)
	// SessionByIDem returns the session a creator already created under key.
	SessionByIDem(ctx context.Context, ws WorkspaceID, creator ActorID, key string) (Session, error)
	// ListSessions returns one page and the opaque next cursor ("" at the
	// end).
	ListSessions(ctx context.Context, ws WorkspaceID, q SessionQuery) ([]Session, string, error)
	// Transition moves id from any state in from to to, optionally updating
	// the transition columns. ErrConflict when the current state is not in
	// from; ErrNotFound when id does not exist. When opts.RunnerID names a
	// runner the repository also advances PlacementGeneration (see Session).
	Transition(ctx context.Context, ws WorkspaceID, id SessionID, from []SessionState, to SessionState, opts TransitionOpts) error
	// SetSessionSetupHash records the setup a session was dispatched with.
	SetSessionSetupHash(ctx context.Context, ws WorkspaceID, id SessionID, hash string) error
	// SetChildExitCode records the exit status of a session's agent process.
	SetChildExitCode(ctx context.Context, ws WorkspaceID, id SessionID, code int) error
	// NextControllerGeneration advances id's controller generation by one and
	// returns the new value, atomically with respect to every other caller.
	// ErrNotFound when id does not exist in ws.
	NextControllerGeneration(ctx context.Context, ws WorkspaceID, id SessionID) (uint64, error)
}

SessionRepository is the workspace-keyed session persistence port. Every method mirrors one semantic read or transition the existing application behavior performs, mapped from internal/controld.Store as follows:

CreateSession        → Store.CreateSession
GetSession           → Store.GetSession
SessionByIDem        → Store.SessionByIdem (idempotency replay)
ListSessions         → Store.ListSessions
Transition           → Store.Transition
SetSessionSetupHash  → Store.SetSessionSetupHash
SetChildExitCode     → Store.SetChildExitCode

NextControllerGeneration has no Store predecessor: the controller lease was process memory and is now the repository's, so a restart or a second replica cannot hand out the same authority twice.

User, token, secret, and credential operations are deliberately absent: they belong to identity and vault adapters, not to the application service.

type SessionState

type SessionState string

SessionState is a session's lifecycle state. The vocabulary and the Terminal/OccupiesSlot predicates are carried byte-for-byte from the internal/controld definition so the extracted application service cannot drift from today's behavior; the extraction lanes remove the internal copy after this freeze.

const (
	StateQueued        SessionState = "queued"
	StateCreating      SessionState = "creating"
	StateRunning       SessionState = "running"
	StateSuspendedWarm SessionState = "suspended_warm"
	StateSuspendedCold SessionState = "suspended_cold"
	StateCanceled      SessionState = "canceled"
	StateFailed        SessionState = "failed"
	StateDead          SessionState = "dead"
	StateDestroyed     SessionState = "destroyed"
)

func (SessionState) OccupiesSlot

func (s SessionState) OccupiesSlot() bool

OccupiesSlot reports whether a session in state s counts against a runner's capacity: creating, running, or suspended_warm.

func (SessionState) Terminal

func (s SessionState) Terminal() bool

Terminal reports whether s is out of the schedulable lifecycle and hidden from the default list: canceled, failed, dead, or destroyed.

type Sessions

type Sessions interface {
	CreateSession(context.Context, Scope, CreateSession) (Session, error)
	GetSession(context.Context, Scope, SessionID) (Session, error)
	ListSessions(context.Context, Scope, SessionQuery) (SessionPage, error)
	DeleteSession(context.Context, Scope, DeleteSession) error
	SuspendSession(context.Context, Scope, SuspendSession) (Session, error)
	ResumeSession(context.Context, Scope, ResumeSession) (Session, error)
	SnapshotSession(context.Context, Scope, SnapshotSession) (Checkpoint, error)
}

Sessions is the session half of the caller-facing application contract. Every method receives a host-created Scope; authorization is an Authorizer call made before any state disclosure or side effect.

type SnapshotSession

type SnapshotSession struct {
	ID SessionID
}

SnapshotSession is the command for SnapshotSession.

type SuspendSession

type SuspendSession struct {
	ID   SessionID
	Warm bool
}

SuspendSession is the command for SuspendSession. Warm selects a warm suspend (container paused in place) over a cold one (container stopped, state checkpointed).

type TerminalStream

type TerminalStream interface {
	Receive(context.Context) (terminal.ClientMessage, error)
	Send(context.Context, terminal.ServerMessage) error
	Close(error) error
}

TerminalStream is the transport adapter over complete terminal protocol messages — not a socket. The application authorizes before calling the attachment broker and does not log or persist stream messages.

type TransitionOpts

type TransitionOpts struct {
	RunnerID *RunnerID
	Error    *string
	// Image, when non-nil, records the image this placement resolved for the
	// session (Spec.Image): the cached checkpoint on a runner that holds it,
	// else the environment's own image. Set only by a placement transition.
	Image *string
}

TransitionOpts carries the columns a guarded session transition may update alongside state. A nil field leaves that column unchanged.

type UnitOfWork

type UnitOfWork interface {
	Run(ctx context.Context, fn func(ctx context.Context) error) error
}

UnitOfWork is the host's atomicity: Run executes fn so that every repository write and event record fn makes through the context it is handed commits together or not at all. A nested Run joins the enclosing unit rather than starting another. A host without transactions (an in-memory store) runs fn directly. Run returns fn's error unchanged, and ErrUnavailable when the unit itself cannot be opened or committed; no transaction, connection, or driver type crosses this port.

type UpdateEnvironment

type UpdateEnvironment struct {
	ID              EnvironmentID
	Name            *string
	Image           *string
	Setup           *string
	Init            *string
	InitTimeoutSec  *int
	EgressAllow     *[]string
	SecretRefs      *[]string
	Connectors      *[]Connector
	Requirements    *Requirements
	SetupTimeoutSec *int
}

UpdateEnvironment is the command for UpdateEnvironment. Pointer fields distinguish "leave this column alone" (nil) from "set it to the zero value" (a non-nil pointer): clearing a list and keeping it are different requests. ID selects the environment.

type Usage

type Usage struct {
	CPUTimeSeconds    float64
	MemoryByteSeconds int64
	StorageBytes      int64
	NetworkBytes      int64
	AgentTokenCount   int64
}

Usage is the provider-neutral resource/usage fact set an Event may carry: CPU time, memory byte-seconds, storage and network bytes, and agent token counts when available. It never includes a provider rate or a customer charge.

type WorkspaceDiff

type WorkspaceDiff struct {
	SessionID SessionID
}

WorkspaceDiff is the command for WorkspaceDiff: the session's per-repository diff, straight from the sandbox, bounded by the public workspace contract.

type WorkspaceID

type WorkspaceID string

The typed identity vocabulary. Every identity in the control contract is a distinct named string type so a workspace, an actor, a session, an environment, a pool, a runner, and an event can never be assigned to one another by accident. Provider-native identifiers are never represented: a pool and a runner are opaque Rainier identities, and an adapter maps them to whatever the provider uses.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL