store

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 20, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package store defines the transactional persistence contract used by kernel controllers. Infrastructure implementations must preserve these semantics.

Index

Constants

View Source
const (
	// IPCPayloadLimit bounds one message's JSON payload. A message event
	// travels through outbox_events to NATS, whose stream caps one message at
	// 1 MiB (internal/platform/outbox/jetstream.go), so the payload stays well
	// below that and larger content must travel as an attachment reference.
	IPCPayloadLimit = 256 << 10

	// IPCMessageEventAggregateType is the outbox aggregate type of the event
	// that announces a stored message. The outbox renders subjects as
	// "fenced.events.<aggregate_type lowercased>.<event_type lowercased>" and
	// requires both tokens to match ^[A-Za-z][A-Za-z0-9_]{0,127}$, so the value
	// is pinned here before any delivery code exists: it may not contain '.' or
	// '-'.
	IPCMessageEventAggregateType = "ipc"

	// IPCMessageStoredEventType is the outbox event type of the notification
	// that announces a stored message. Like the aggregate type it is pinned
	// before the delivery code exists, because the outbox renders both into one
	// NATS subject ("fenced.events.ipc.messagestored") and validates each token
	// against ^[A-Za-z][A-Za-z0-9_]{0,127}$.
	//
	// The event announces that a message reached a mailbox. It does not mean the
	// message was delivered to a receiver: the runtime protocol is pull-only, so
	// a receiver observes its mailbox when it chooses to drain it and the
	// platform has no way to notify it.
	IPCMessageStoredEventType = "MessageStored"
)
View Source
const (
	// MemoryContentLimit is the canonical store's per-record content cap.
	MemoryContentLimit = 256 << 10
	// MemoryEmbeddingDimension is the v0.1 vector space dimension.
	MemoryEmbeddingDimension = 384
)
View Source
const AuditSchema = "fenced.audit/v1"

AuditSchema identifies the canonical audit event encoding.

Variables

View Source
var (
	// ErrAgentVersionConflict reports a publish attempt that reuses an
	// existing (tenant, name, version) identity with a different spec.
	ErrAgentVersionConflict = errors.New("agent version identity already published with a different spec")
	// ErrAgentVersionRefInvalid reports a reference that is not a canonical
	// name@version token pair.
	ErrAgentVersionRefInvalid = errors.New("agent version reference is not canonical")
)
View Source
var (
	// ErrBudgetExceeded reports a usage settlement that would push a task past
	// its reserved ceiling. The settlement is rejected and the ledger is
	// marked exhausted: new consumption must stop.
	ErrBudgetExceeded = errors.New("task budget would be exceeded")
	// ErrBudgetNotReserved reports a settlement or read for a task without a
	// budget reservation.
	ErrBudgetNotReserved = errors.New("task has no budget reservation")
	// ErrUsageReservationConflict reports a replay that changes the amount
	// reserved under an existing reservation key.
	ErrUsageReservationConflict = errors.New("usage reservation conflicts with its replay")
)
View Source
var (
	// ErrIPCAddressUnscoped reports an address that names only an agent
	// version. Mailboxes are instance-scoped: a version-only address would be
	// drained by whichever instance polls first, which is a competing-consumer
	// semantic the v1 contract does not define.
	ErrIPCAddressUnscoped = errors.New("ipc address must name an instance")
	// ErrIPCPayloadTooLarge reports a payload above IPCPayloadLimit.
	ErrIPCPayloadTooLarge = errors.New("ipc payload exceeds the mailbox limit")
	// ErrIPCDeadlineElapsed reports a deadline that does not lie after SentAt:
	// such a message would be born already expired, which is a caller bug
	// rather than a message to store.
	ErrIPCDeadlineElapsed = errors.New("ipc message deadline has already elapsed")
)
View Source
var (
	// ErrModelNotFound reports a model descriptor that is not registered in
	// the tenant's registry.
	ErrModelNotFound = errors.New("model descriptor not found")
	// ErrModelSpecConflict reports a registration that reuses an existing
	// (tenant, provider, model) identity with a different spec.
	ErrModelSpecConflict = errors.New("model identity already registered with a different spec")
	// ErrModelCallTerminal reports usage settlement or finishing on a call
	// that already reached a terminal state.
	ErrModelCallTerminal = errors.New("model call already reached a terminal state")
)
View Source
var (
	ErrNoAssignment    = fmt.Errorf("no runtime assignment available")
	ErrLeaseNotExpired = fmt.Errorf("runtime lease has not expired")
)
View Source
var (
	ErrNotFound            = errors.New("kernel object not found")
	ErrVersionConflict     = errors.New("resource version conflict")
	ErrInvalidTransition   = errors.New("invalid lifecycle transition")
	ErrIdempotencyConflict = errors.New("idempotency key reused with different request")
	ErrLeaseHeld           = errors.New("run already has an active lease")
	ErrFenced              = errors.New("attempt fencing token is stale")
	ErrCompletionPending   = errors.New("completed attempt is awaiting result commit")
	ErrResultRequired      = errors.New("durable result reference is required")
	// ErrRetryableTransaction marks a transient serialization failure that
	// callers must retry with bounded backoff (ADR-002: SERIALIZABLE with
	// bounded retries).
	ErrRetryableTransaction = errors.New("retryable transaction conflict")
)
View Source
var (
	// ErrToolNotFound reports a tool descriptor that is not registered in the
	// tenant's registry.
	ErrToolNotFound = errors.New("tool descriptor not found")
	// ErrToolSpecConflict reports a registration that reuses an existing
	// (tenant, name, version) identity with a different spec.
	ErrToolSpecConflict = errors.New("tool version identity already registered with a different spec")
	// ErrApprovalNotUsable reports an approval that cannot authorize an
	// invocation: wrong binding, expired, or not approved.
	ErrApprovalNotUsable = errors.New("approval cannot authorize this invocation")
)
View Source
var (
	// ErrWorkflowNotFound reports a workflow outside the tenant's scope.
	ErrWorkflowNotFound = errors.New("workflow not found")
	// ErrStepNotFound reports a step that does not belong to the workflow.
	ErrStepNotFound = errors.New("workflow step not found")
)
View Source
var AuditGenesisHash = sha256.Sum256([]byte("fenced-audit-genesis-v1"))

AuditGenesisHash anchors the first event of every tenant's chain: the first event's PrevHash equals this constant, so a truncated chain (events deleted from the head) is detectable.

View Source
var ErrAuditChainBroken = errors.New("audit chain integrity check failed")

ErrAuditChainBroken reports a hash-chain integrity failure at a known seq.

View Source
var ErrCapacityExhausted = errors.New("runtime pool capacity exhausted")
View Source
var ErrMemoryNotFound = errors.New("memory record not found")

ErrMemoryNotFound reports a memory record that does not exist in the tenant's scope.

View Source
var ErrMemorySearchRequired = errors.New("memory search requires a keyword query or an embedding")

ErrMemorySearchRequired reports a search with neither a keyword query nor an embedding vector.

View Source
var ErrMemoryTooLarge = errors.New("memory content exceeds 256 KiB")

ErrMemoryTooLarge reports content that exceeds the canonical store limit.

View Source
var ErrPoolCapacityNotInitialized = errors.New("runtime pool capacity ledger is not initialized")

ErrPoolCapacityNotInitialized is returned when placement targets a pool whose durable capacity ledger row has not been registered by the runtime pool registry. Scheduling fails closed instead of bootstrapping totals from a caller snapshot.

View Source
var ErrPoolOperatorDenied = errors.New("runtime pool operator grant is required")

ErrPoolOperatorDenied reports a pool status change attempted by a principal without an operator grant. Tenant usage grants never imply operator authority on shared pools.

View Source
var ErrSpawnDenied = errors.New("spawn denied")

ErrSpawnDenied reports a dynamic-spawn guard rejection.

View Source
var ErrTenantQuotaExceeded = errors.New("tenant aggregate consumption quota would be exceeded")

ErrTenantQuotaExceeded reports an admission that would push a tenant's windowed aggregate consumption past its configured limits. The admission is rejected and nothing is recorded; the task stays queued and is rejected with a recorded TENANT_QUOTA_EXCEEDED decision on the next claim round.

View Source
var MemorySensitivities = map[string]struct{}{
	"internal": {}, "confidential": {}, "restricted": {},
}

MemorySensitivities are the v0.1 sensitivity tiers; retrieval filters on them before scoring (ADR-009: the ACL check runs before retrieval).

Functions

func CanTransitionModelCall

func CanTransitionModelCall(from, to ModelCallStatus) bool

CanTransitionModelCall defines the model-call state machine.

func CanTransitionStep

func CanTransitionStep(from, to StepStatus) bool

CanTransitionStep defines the step state machine. RUNNING → PENDING is the single-step retry path; it never touches sibling steps.

func CanTransitionTo

func CanTransitionTo(from, to ToolCallStatus) bool

CanTransitionTo defines the decision-ledger state machine.

func CanTransitionWorkflow

func CanTransitionWorkflow(from, to WorkflowStatus) bool

CanTransitionWorkflow defines the workflow state machine.

func DenialCode

func DenialCode(err error) (string, bool)

DenialCode extracts the stable denial code of a spawn error, if any.

func IPCMailboxConsumerName

func IPCMailboxConsumerName(runID string) string

IPCMailboxConsumerName renders the inbox_receipts consumer name a drain of the mailbox for runID must use. Receipts are keyed by (tenant, consumer name, message id), so scoping the name to the receiving run is what makes a redelivery idempotent without letting one run's receipt hide a message from another run's drain.

func IsRetryableTransaction

func IsRetryableTransaction(err error) bool

IsRetryableTransaction reports whether err is a transient transaction failure that may be retried with backoff.

func QuotaExceeded

func QuotaExceeded(limits, consumed, additional TaskBudget) bool

QuotaExceeded reports whether additional usage would push a tenant's windowed consumption past any configured limit. A limit of 0 means the dimension is unlimited.

func QuotaReservationExceeded

func QuotaReservationExceeded(limits, consumed, reserved, additional TaskBudget) bool

QuotaReservationExceeded is the v0.8 admission gate: additional usage is rejected when consumed plus the reserved ceilings of in-flight tasks plus the additional ceiling would exceed any limit. Reservation closes the concurrent-admission overshoot of the v0.6 consumed-only gate.

func RetryRetryable

func RetryRetryable(ctx context.Context, fn func() (int, error)) (int, error)

RetryRetryable runs fn, retrying transient transaction conflicts with bounded exponential backoff (ADR-002: SERIALIZABLE with bounded retries). Non-retryable errors and context cancellation return immediately.

func SpawnKeyHash

func SpawnKeyHash(arguments json.RawMessage) string

SpawnKeyHash fingerprints the spawn arguments into the idempotent spawn_key suffix.

func TaskSpecBudgetReservation

func TaskSpecBudgetReservation(spec json.RawMessage) (tokens int64, costMicroUSD money.MicroUSD)

TaskSpecBudgetReservation extracts the token and cost ceiling a merged workflow step spec will reserve at admission. It mirrors the admission controller's workload budget decode so the step reservation equals the task ledger reservation that later replaces it.

func TenantShard

func TenantShard(tenantID string, count int) int

TenantShard returns the ADR-016 shard for a tenant: the first 32 bits of md5(tenant_id) modulo count. It mirrors the SQL expression used by ClaimTasks exactly, so tests can assert the filter deterministically. md5 is used instead of hashing functions like hashtext, which PostgreSQL does not guarantee stable across major versions.

func ValidateModelRef

func ValidateModelRef(ref string) error

ValidateModelRef rejects model references that are not safe canonical provider/model tokens.

func ValidateStepName

func ValidateStepName(name string) error

ValidateStepName rejects step names that are not canonical tokens.

func ValidateToolName

func ValidateToolName(name string) error

ValidateToolName rejects tool names that are not safe canonical tokens.

Types

type AcknowledgeIPCMessagesInput

type AcknowledgeIPCMessagesInput struct {
	TenantID       string
	ConsumerName   string
	MessageIDs     []uuid.UUID
	AcknowledgedAt time.Time
}

AcknowledgeIPCMessagesInput records that a consumer has observed a batch of messages, so a later drain does not return them again.

func (AcknowledgeIPCMessagesInput) Validate

func (in AcknowledgeIPCMessagesInput) Validate() error

Validate rejects an acknowledgement that cannot be applied as asked.

type AcknowledgeIPCMessagesResult

type AcknowledgeIPCMessagesResult struct {
	Acknowledged        []uuid.UUID
	AlreadyAcknowledged []uuid.UUID
}

AcknowledgeIPCMessagesResult partitions the batch into receipts this call created and receipts an earlier call had already created. Both are applied; the split exists so a retry can be told apart from a first attempt.

type AcquireAttemptInput

type AcquireAttemptInput struct {
	TenantID           string
	AttemptID          uuid.UUID
	LeaseID            uuid.UUID
	RunID              uuid.UUID
	ExpectedRunVersion int64
	RuntimeClass       string
	RuntimeInstanceID  string
	TTL                time.Duration
}

type AdmissionReason

type AdmissionReason struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	Field   string `json:"field,omitempty"`
}

type AgentAddress

type AgentAddress struct {
	AgentVersionRef string
	Instance        string
}

AgentAddress names one mailbox. AgentVersionRef is an immutable reference in agentversion.FormatRef form ("[namespace/]name@version"), not a mutable agent name. Instance is the receiving run id, never an attempt id: an attempt is a replaceable execution attempt of a run, so addressing the attempt would orphan every message the moment that attempt failed.

func ParseAgentAddress

func ParseAgentAddress(canonical string) (AgentAddress, error)

ParseAgentAddress splits the canonical form written by Canonical.

func (AgentAddress) Canonical

func (a AgentAddress) Canonical() string

Canonical renders the stored form of the address. The round trip through ParseAgentAddress is total: Validate rejects any segment containing the separator, so the split cannot be ambiguous.

func (AgentAddress) Validate

func (a AgentAddress) Validate() error

Validate reports whether the address names a single mailbox. A version-only address is rejected with ErrIPCAddressUnscoped.

type AgentVersion

type AgentVersion struct {
	ID               uuid.UUID
	TenantID         string
	Namespace        string
	Name             string
	Version          string
	Spec             json.RawMessage
	SpecDigest       [sha256.Size]byte
	ResourceVersion  int64
	CreatedAt        time.Time
	PackageSignature *PackageSignature
}

AgentVersion is an immutable published agent specification. The resource version is always 1: upgrades create new rows instead of mutating this one.

func (AgentVersion) Ref

func (v AgentVersion) Ref() string

Ref returns the canonical reference used by tasks. The default namespace is elided so historical "name@version" references are unchanged; any other namespace is written as "namespace/name@version" (P1-07).

type AgentVersionStore

type AgentVersionStore interface {
	CreateAgentVersion(context.Context, CreateAgentVersionInput) (CreateAgentVersionResult, error)
	GetAgentVersion(context.Context, string, uuid.UUID) (AgentVersion, error)
	GetAgentVersionByRef(context.Context, string, string) (AgentVersion, error)
}

type AppendIPCMessageInput

type AppendIPCMessageInput struct {
	TenantID            string
	ID                  uuid.UUID
	FromAgentVersionRef string
	To                  AgentAddress
	Kind                string
	// Payload is the message body as a JSON document. An empty body is
	// written as {}.
	Payload json.RawMessage
	// Attachments is a JSON array of reference objects. It is stored without
	// being interpreted; a payload above IPCPayloadLimit must travel this way.
	Attachments   json.RawMessage
	CorrelationID string
	// ReplyToMessageID is uuid.Nil when the message is not a reply.
	ReplyToMessageID uuid.UUID
	IdempotencyKey   string
	TraceID          string
	SentAt           time.Time
	// Deadline is optional; the zero time stores no deadline.
	Deadline time.Time
}

AppendIPCMessageInput stores one message in the recipient's mailbox.

ID and SentAt are caller-supplied, not generated here: a send retried after a connection failure must resolve to the message the first attempt created and must report the original send time, so both fields have to survive the retry unchanged.

func (AppendIPCMessageInput) Validate

func (in AppendIPCMessageInput) Validate() error

Validate rejects a message that cannot be stored as asked. Every check is a function of the input alone, never of the wall clock, so replaying the same logical send reaches the same verdict however long the retry took.

type AppendIPCMessageResult

type AppendIPCMessageResult struct {
	Message  IPCMessage
	Replayed bool
}

AppendIPCMessageResult reports the stored message. Replayed is true when the idempotency key resolved to a message an earlier attempt had already stored, in which case Message is that original message rather than a new one.

type ArtifactReference

type ArtifactReference struct {
	ID        uuid.UUID
	URI       string
	SHA256    [sha256.Size]byte
	SizeBytes int64
	MediaType string
}

func (ArtifactReference) DigestHex

func (a ArtifactReference) DigestHex() string

func (ArtifactReference) Validate

func (a ArtifactReference) Validate() error

type Attempt

type Attempt struct {
	ID                uuid.UUID
	TenantID          string
	RunID             uuid.UUID
	Ordinal           int
	Phase             domain.AttemptPhase
	RuntimeClass      string
	RuntimePoolID     string
	RuntimeInstanceID string
	FencingToken      int64
	FailureCode       string
	FailureMessage    string
	ResourceVersion   int64
	CreatedAt         time.Time
	UpdatedAt         time.Time
	StartedAt         *time.Time
	FinishedAt        *time.Time
}

type AttemptLease

type AttemptLease struct {
	Attempt Attempt
	Lease   Lease
	Run     Run
}

type AuditEvent

type AuditEvent struct {
	ID           uuid.UUID
	TenantID     string
	Seq          int64
	PrevHash     [sha256.Size]byte
	ChainHash    [sha256.Size]byte
	EventType    string
	ResourceType string
	ResourceID   uuid.UUID
	Actor        string
	Details      json.RawMessage
	OccurredAt   time.Time
}

AuditEvent is one transactional append-only audit record.

func (AuditEvent) ComputeChainHash

func (e AuditEvent) ComputeChainHash() [sha256.Size]byte

ComputeChainHash returns the canonical chain hash of the event: the value the next event's PrevHash must equal. The encoding is length-prefixed so the concatenation is unambiguous regardless of field content.

type AuditStore

type AuditStore interface {
	ListAudit(context.Context, ListAuditInput) ([]AuditEvent, error)
	GetAuditEvent(context.Context, string, uuid.UUID) (AuditEvent, error)
	VerifyAuditChain(context.Context, string) (AuditVerification, error)
	ExportAuditChain(context.Context, string) ([]AuditEvent, error)
}

AuditStore is the read surface of the audit ledger.

type AuditVerification

type AuditVerification struct {
	Valid          bool
	Checked        int64
	FirstBrokenSeq int64 // 0 when the chain is valid
	HeadSeq        int64
	HeadHash       [sha256.Size]byte
}

AuditVerification is the result of a full chain integrity walk.

type BudgetStore

type BudgetStore interface {
	// GetTaskBudget returns the reservation and cumulative consumption of a
	// task, or ErrBudgetNotReserved when the task carries no budget.
	GetTaskBudget(context.Context, string, uuid.UUID) (TaskBudgetStatus, error)
	// SettleTaskUsage appends one idempotent usage settlement. A settlement
	// that would exceed the reservation is rejected with ErrBudgetExceeded and
	// marks the ledger exhausted without being recorded. Replays of an
	// already-recorded settlement return the current status.
	SettleTaskUsage(context.Context, SettleTaskUsageInput) (TaskBudgetStatus, error)
	// SettleTaskUsageDelta settles the remainder between a family's already
	// settled usage and a cumulative target, exactly once per IdempotencyKey.
	// The hard stop and replay semantics match SettleTaskUsage; a family that
	// already settled at least the target settles nothing.
	SettleTaskUsageDelta(context.Context, SettleTaskUsageDeltaInput) (TaskBudgetStatus, error)
	// ReserveTaskUsage atomically protects headroom before a provider or tool
	// call starts. Replays with the same key and amount are idempotent.
	ReserveTaskUsage(context.Context, ReserveTaskUsageInput) error
	// ReleaseTaskUsageReservation is idempotent and must run on every terminal
	// call path. Expired reservations are reclaimed by reconciliation.
	ReleaseTaskUsageReservation(context.Context, string, uuid.UUID, string) error
}

type CancelAttemptInput

type CancelAttemptInput struct {
	TenantID               string
	AttemptID              uuid.UUID
	FencingToken           int64
	ExpectedAttemptVersion int64
	IdempotencyKey         string
}

func (CancelAttemptInput) RequestHash

func (in CancelAttemptInput) RequestHash() ([sha256.Size]byte, error)

type CancelAttemptResult

type CancelAttemptResult struct {
	Attempt Attempt
	Run     Run
	Task    Task
}

type Checkpoint

type Checkpoint struct {
	ID                  uuid.UUID
	TenantID            string
	RunID               uuid.UUID
	AttemptID           uuid.UUID
	Ordinal             int
	FencingToken        int64
	AgentVersionRef     string
	RuntimeClass        string
	Provider            string
	RuntimeABI          string
	SchemaVersion       string
	State               ArtifactReference
	ConfirmedReceiptIDs []string
	EnvelopeSHA256      [sha256.Size]byte
	CreatedAt           time.Time
}

type ClaimOutboxInput

type ClaimOutboxInput struct {
	DispatcherID string
	Limit        int
	LockTTL      time.Duration
}

type ClaimTasksInput

type ClaimTasksInput struct {
	Kind    ControllerKind
	Phase   domain.TaskPhase
	OwnerID string
	Limit   int
	TTL     time.Duration
	// ShardIndex / ShardCount are the tenant-consistent shard filter
	// (ADR-016): when ShardCount > 0, only tasks whose tenant maps to
	// ShardIndex are claimable. Zero values mean no sharding (every instance
	// claims every tenant). All instances must share the same shard count.
	ShardIndex int
	ShardCount int
}

type ClaimWorkflowsInput

type ClaimWorkflowsInput struct {
	Owner     string
	Batch     int
	Lease     time.Duration
	MaxTokens int64
}

ClaimWorkflowsInput bounds one orchestrator claim round.

type CommitCheckpointInput

type CommitCheckpointInput struct {
	TenantID               string
	AttemptID              uuid.UUID
	FencingToken           int64
	ExpectedAttemptVersion int64
	IdempotencyKey         string
	CheckpointID           uuid.UUID
	AgentVersionRef        string
	Provider               string
	RuntimeABI             string
	SchemaVersion          string
	State                  ArtifactReference
	ConfirmedReceiptIDs    []string
}

func (CommitCheckpointInput) Normalize

type CompleteAttemptInput

type CompleteAttemptInput struct {
	TenantID               string
	AttemptID              uuid.UUID
	FencingToken           int64
	ExpectedAttemptVersion int64
	IdempotencyKey         string
	Result                 ArtifactReference
}

func (CompleteAttemptInput) RequestHash

func (in CompleteAttemptInput) RequestHash() ([sha256.Size]byte, error)

type CompleteAttemptResult

type CompleteAttemptResult struct {
	Attempt Attempt
	Run     Run
	Task    Task
}

type CompleteRunInput

type CompleteRunInput struct {
	TenantID           string
	RunID              uuid.UUID
	AttemptID          uuid.UUID
	FencingToken       int64
	ExpectedRunVersion int64
	ResultRef          string
}

type ControlStore

type ControlStore interface {
	GetTask(context.Context, string, uuid.UUID) (Task, error)
	ClaimTasks(context.Context, ClaimTasksInput) ([]TaskClaim, error)
	ReleaseTaskClaim(context.Context, TaskClaim) error
	DecideAdmission(context.Context, DecideAdmissionInput) (Task, error)
	ScheduleTask(context.Context, ScheduleTaskInput) (AttemptLease, error)
	DeferTaskSchedule(context.Context, DeferTaskScheduleInput) (Task, error)
	ClaimOutbox(context.Context, ClaimOutboxInput) ([]OutboxEvent, error)
	MarkOutboxPublished(context.Context, uuid.UUID, string, int64, time.Time) error
	MarkOutboxFailed(context.Context, uuid.UUID, string, int64, string, time.Time) error
	GetAgentVersionByRef(context.Context, string, string) (AgentVersion, error)
}

type ControllerKind

type ControllerKind string
const (
	ControllerAdmission  ControllerKind = "ADMISSION"
	ControllerScheduling ControllerKind = "SCHEDULING"
)

type CreateAgentVersionInput

type CreateAgentVersionInput struct {
	ID               uuid.UUID
	TenantID         string
	Namespace        string
	Name             string
	Version          string
	Spec             json.RawMessage
	PackageSignature *PackageSignature
}

func (CreateAgentVersionInput) ValidateAndHash

func (in CreateAgentVersionInput) ValidateAndHash() (json.RawMessage, [sha256.Size]byte, error)

ValidateAndHash bounds the publication and derives the canonical spec document and its immutable digest.

type CreateAgentVersionResult

type CreateAgentVersionResult struct {
	AgentVersion AgentVersion
	Existing     bool
}

type CreateModelCallInput

type CreateModelCallInput struct {
	ID        uuid.UUID
	TenantID  string
	TaskID    uuid.UUID
	RunID     uuid.UUID
	AttemptID uuid.UUID
	ModelRef  string
	// PriceRevision pins the price table the call is metered against.
	PriceRevision  string
	IdempotencyKey string
}

func (CreateModelCallInput) RequestHash

func (in CreateModelCallInput) RequestHash() ([sha256.Size]byte, error)

type CreateModelCallResult

type CreateModelCallResult struct {
	ModelCall ModelCall
	Existing  bool
}

type CreateRunInput

type CreateRunInput struct {
	ID                  uuid.UUID
	TenantID            string
	TaskID              uuid.UUID
	ExpectedTaskVersion int64
}

type CreateTaskInput

type CreateTaskInput struct {
	ID               uuid.UUID
	TenantID         string
	Namespace        string
	AgentVersionRef  string
	Goal             string
	Spec             json.RawMessage
	IdempotencyKey   string
	WorkflowID       *uuid.UUID
	WorkflowStepID   *uuid.UUID
	WorkflowStepName string
	WorkflowAttempt  int
	ParentTaskID     *uuid.UUID
}

func (CreateTaskInput) ValidateAndHash

func (in CreateTaskInput) ValidateAndHash() (json.RawMessage, [32]byte, error)

type CreateTaskResult

type CreateTaskResult struct {
	Task     Task
	Existing bool
}

type CreateToolApprovalInput

type CreateToolApprovalInput struct {
	ID          uuid.UUID
	TenantID    string
	CallID      uuid.UUID
	TaskID      uuid.UUID
	RunID       uuid.UUID
	AttemptID   uuid.UUID
	ToolName    string
	ToolVersion string
	Action      string
	Resource    string
	ArgsHash    [sha256.Size]byte
	RequestedAt time.Time
	ExpiresAt   time.Time
}

type CreateToolApprovalResult

type CreateToolApprovalResult struct {
	ToolApproval ToolApproval
	Existing     bool
}

type CreateToolCallInput

type CreateToolCallInput struct {
	ID             uuid.UUID
	TenantID       string
	TaskID         uuid.UUID
	RunID          uuid.UUID
	AttemptID      uuid.UUID
	ToolName       string
	ToolVersion    string
	Action         string
	Resource       string
	ArgsHash       [sha256.Size]byte
	IdempotencyKey string
}

func (CreateToolCallInput) RequestHash

func (in CreateToolCallInput) RequestHash() ([sha256.Size]byte, error)

RequestHash is the canonical digest of the invocation intent, used to detect idempotency-key reuse with different semantics.

type CreateToolCallResult

type CreateToolCallResult struct {
	ToolCall ToolCall
	Existing bool
}

type CreateWorkflowInput

type CreateWorkflowInput struct {
	ID             uuid.UUID
	TenantID       string
	Namespace      string
	IdempotencyKey string
	Goal           string
	Spec           json.RawMessage
	Steps          []CreateWorkflowStepInput
	// Budget ceilings decoded from the workflow document; zero leaves
	// the dimension unbounded.
	BudgetMaxTasks        int64
	BudgetMaxTokens       int64
	BudgetMaxCostMicroUSD money.MicroUSD
	DeadlineAt            *time.Time
}

CreateWorkflowInput creates a workflow and its steps atomically.

func (CreateWorkflowInput) RequestHash

func (in CreateWorkflowInput) RequestHash() ([sha256.Size]byte, error)

RequestHash fingerprints the tenant-scoped workflow definition so an idempotency-key replay of a different definition is rejected.

type CreateWorkflowResult

type CreateWorkflowResult struct {
	Workflow Workflow
	Existing bool
}

CreateWorkflowResult reports the created workflow and whether an idempotency-key replay returned the existing definition.

type CreateWorkflowStepInput

type CreateWorkflowStepInput struct {
	Name              string
	Spec              json.RawMessage // per-step workload spec overlay
	AgentVersionRef   string
	Goal              string
	DependsOn         []string
	ConditionStep     string
	ConditionContains string
	ConditionEquals   string
	RequiresApproval  bool
	MaxAttempts       int
}

CreateWorkflowStepInput is one declared step of a new workflow.

type DecideAdmissionInput

type DecideAdmissionInput struct {
	TaskID              uuid.UUID
	TenantID            string
	OwnerID             string
	ClaimFencingToken   int64
	ExpectedTaskVersion int64
	Admit               bool
	ReasonCode          string
	Reasons             []AdmissionReason
	EvaluatorVersion    string
	// AgentVersionID binds the task to the immutable published version its
	// reference resolved to. It is set by the admission controller whenever
	// the reference is resolvable, regardless of the admission outcome.
	AgentVersionID *uuid.UUID
	// Budget is the task's reserved ceiling, derived from its workload spec
	// by the admission controller. When set and the task is admitted, the
	// ledger row is created in the same transaction as the admission
	// decision; nil means the task carries no budget.
	Budget *TaskBudget
	// PolicyRevision records the Rego policy revision that produced the
	// decision; empty when no policy engine participated.
	PolicyRevision string
}

type DecideToolApprovalInput

type DecideToolApprovalInput struct {
	TenantID        string
	ApprovalID      uuid.UUID
	ExpectedVersion int64
	Decision        ToolApprovalStatus
	DecidedBy       string
	Now             time.Time
}

func (DecideToolApprovalInput) Valid

func (in DecideToolApprovalInput) Valid() bool

Valid checks the decision request: only APPROVED/REJECTED decisions, an identified decider, and a current clock.

type DecideWorkflowStepApprovalInput

type DecideWorkflowStepApprovalInput struct {
	TenantID        string
	WorkflowID      uuid.UUID
	StepName        string
	ExpectedVersion int64
	Approved        bool
	DecidedBy       string
}

DecideWorkflowStepApprovalInput records a human decision on one step.

type DeferTaskScheduleInput

type DeferTaskScheduleInput struct {
	TaskID              uuid.UUID
	TenantID            string
	OwnerID             string
	ClaimFencingToken   int64
	ExpectedTaskVersion int64
	Until               time.Time
	Rejection           json.RawMessage
}

DeferTaskScheduleInput releases the scheduler's claim on a task that no pool could place and defers its next scheduling attempt until Until (O6). The deferral is recorded on the task — not on the claim — so every controller instance agrees on the backoff, and the claim is deleted in the same transaction (immediate release, no waiting out the claim TTL).

type FinishModelCallInput

type FinishModelCallInput struct {
	TenantID          string
	ModelCallID       uuid.UUID
	ExpectedVersion   int64
	Status            ModelCallStatus
	InputTokens       int64
	OutputTokens      int64
	CostMicroUSD      money.MicroUSD
	PriceRevision     string
	ProviderRequestID string
	FinishReason      string
	UsageCertainty    ModelUsageCertainty
}

FinishModelCallInput finalizes one model invocation with the final usage.

type HeartbeatLeaseInput

type HeartbeatLeaseInput struct {
	TenantID             string
	AttemptID            uuid.UUID
	FencingToken         int64
	ExpectedLeaseVersion int64
	TTL                  time.Duration
}

type HeartbeatStatus

type HeartbeatStatus struct {
	CancelRequested bool
	AttemptVersion  int64
}

HeartbeatStatus is the narrow state a lease renewal needs: whether the task has a pending cancellation and the attempt's current resource version. It lets the Runtime Protocol heartbeat answer cancel checks without re-materializing the full assignment.

type IPCMessage

type IPCMessage struct {
	Sequence            int64
	ID                  uuid.UUID
	TenantID            string
	FromAgentVersionRef string
	To                  AgentAddress
	Kind                string
	Payload             json.RawMessage
	Attachments         json.RawMessage
	CorrelationID       string
	// ReplyToMessageID is uuid.Nil when the message is not a reply.
	ReplyToMessageID uuid.UUID
	TraceID          string
	SentAt           time.Time
	// Deadline is the zero time when the message carries no deadline.
	Deadline time.Time
}

IPCMessage is one durable message in a mailbox. Sequence is the mailbox cursor: it increases inside one mailbox but not by one, because the sequence is global to the table.

type IPCStore

type IPCStore interface {
	// AppendIPCMessage stores one message in the recipient's mailbox. A
	// replay of the same idempotency key returns the message the first attempt
	// stored, with Replayed=true; the same key carrying a different message is
	// ErrIdempotencyConflict.
	//
	// A message that is stored for the first time also enqueues one
	// IPCMessageStoredEventType event into outbox_events in the same
	// transaction. A replay enqueues nothing: the message it resolves to was
	// already announced, and announcing it again would turn one send into two
	// events.
	AppendIPCMessage(context.Context, AppendIPCMessageInput) (AppendIPCMessageResult, error)
	// GetIPCMessage returns one message or ErrNotFound. A message belonging to
	// another tenant is not found.
	GetIPCMessage(context.Context, string, uuid.UUID) (IPCMessage, error)
	// ListMailbox returns the messages addressed to To with a sequence above
	// the cursor that the consumer has not receipted, in mailbox order.
	ListMailbox(context.Context, ListMailboxInput) ([]IPCMessage, error)
	// AcknowledgeIPCMessages records the consumer's receipts for a batch. Only
	// messages that exist in the tenant may be acknowledged: a receipt for an
	// unknown id would hide the real message if it arrived later.
	AcknowledgeIPCMessages(context.Context, AcknowledgeIPCMessagesInput) (AcknowledgeIPCMessagesResult, error)
}

IPCStore is the durable mailbox surface. Delivery is expressed as a side effect of the durable write rather than as a method of its own: AppendIPCMessage enqueues the dispatch event in the same transaction, so a stored message and its announcement cannot diverge. Publishing that event to NATS is the dispatcher's job (internal/platform/outbox), and notifying a receiver is deliberately absent: fenced.runtime.v1 is pull-only, so a receiver drains its mailbox on its own schedule and no method here pretends otherwise.

type Lease

type Lease struct {
	ID              uuid.UUID
	TenantID        string
	RunID           uuid.UUID
	AttemptID       uuid.UUID
	FencingToken    int64
	ResourceVersion int64
	AcquiredAt      time.Time
	HeartbeatAt     time.Time
	ExpiresAt       time.Time
}

type ListAuditInput

type ListAuditInput struct {
	TenantID string
	// AfterSeq returns events with seq > AfterSeq (cursor semantics).
	AfterSeq int64
	Limit    int
}

ListAuditInput pages a tenant's ledger forward by seq.

type ListMailboxInput

type ListMailboxInput struct {
	TenantID string
	To       AgentAddress
	// AfterSequence is exclusive cursor semantics, matching
	// ListAuditInput.AfterSeq.
	AfterSequence int64
	Limit         int
	// ConsumerName scopes the receipt. Messages already receipted for this
	// consumer are not returned. Use IPCMailboxConsumerName to derive it from
	// the receiving run id.
	ConsumerName string
}

ListMailboxInput drains one mailbox forward by sequence.

func (ListMailboxInput) Validate

func (in ListMailboxInput) Validate() error

Validate rejects a drain that could read another mailbox or an unbounded page.

type MailboxScopeStore

type MailboxScopeStore interface {
	// GetRunMailboxScope returns the scope of runID within the tenant, or
	// ErrNotFound when no such run exists in that tenant.
	GetRunMailboxScope(context.Context, string, uuid.UUID) (RunMailboxScope, error)
}

MailboxScopeStore resolves the run an address names. It is separate from IPCStore because it reads the run/task tables rather than the mailbox, and because a send needs it before it has anything to store: without the check, a sender that mistypes a run id stores a message into a mailbox that is never drained, and nothing reports it.

type MemoryRecord

type MemoryRecord struct {
	ID                uuid.UUID
	TenantID          string
	Namespace         string
	Key               string
	ContentType       string
	Content           string
	Embedding         []float32
	EmbeddingProvider string
	Sensitivity       string
	SourceTaskID      *uuid.UUID
	SourceRunID       *uuid.UUID
	SourceAttemptID   *uuid.UUID
	Provenance        json.RawMessage
	RetentionUntil    *time.Time
	TombstoneAt       *time.Time
	SupersededBy      *uuid.UUID
	ResourceVersion   int64
	CreatedAt         time.Time
	UpdatedAt         time.Time
}

MemoryRecord is one canonical memory entry: identity, provenance, ACL, tenant, sensitivity, version, retention and tombstone state. Content lives in PostgreSQL for v0.1 (FTS + pgvector share the transaction system); large payloads move to the object store behind the same interface later.

func (MemoryRecord) ContentHash

func (r MemoryRecord) ContentHash() ([sha256.Size]byte, error)

ContentHash returns the SHA-256 of the canonical memory document; a PutMemory with the same (tenant, namespace, key) and an identical document replays idempotently instead of creating a new version. Nil provenance is canonicalized to {} and retention times to UTC so stored and submitted documents hash identically.

type MemoryStore

type MemoryStore interface {
	// PutMemory inserts or updates the record with the given stable
	// (tenant, namespace, key). An identical document replays idempotently
	// (Existing=true, no version bump); a different document is a new
	// version (correction) and resurrects a tombstoned record.
	PutMemory(context.Context, PutMemoryInput) (MemoryRecord, bool, error)
	// GetMemory returns the record (including tombstone state) or
	// ErrMemoryNotFound.
	GetMemory(context.Context, string, uuid.UUID) (MemoryRecord, error)
	// SearchMemory returns live (non-tombstoned, unexpired) records scored
	// by keyword FTS/trigram similarity and optional vector cosine distance,
	// tenant- and sensitivity-filtered before scoring.
	SearchMemory(context.Context, SearchMemoryInput) ([]MemoryRecord, error)
	// TombstoneMemory soft-deletes a record (ADR-009 deletion intent), CAS on
	// resource version.
	TombstoneMemory(context.Context, string, uuid.UUID, int64) (MemoryRecord, error)
}

type MetricsStore

type MetricsStore interface {
	AggregateMetrics(context.Context, string, time.Time) (*observability.Metrics, error)
}

MetricsStore exposes the aggregated platform observability surface (§Phase-7 core metrics), consistent with the data the store's AggregateMetrics method produces.

type ModelCall

type ModelCall struct {
	ID                uuid.UUID
	TenantID          string
	TaskID            uuid.UUID
	RunID             uuid.UUID
	AttemptID         uuid.UUID
	ModelRef          string
	Status            ModelCallStatus
	IdempotencyKey    string
	RequestHash       [sha256.Size]byte
	InputTokens       int64
	OutputTokens      int64
	CostMicroUSD      money.MicroUSD
	PriceRevision     string
	ProviderRequestID string
	FinishReason      string
	UsageCertainty    ModelUsageCertainty
	ResourceVersion   int64
	CreatedAt         time.Time
	UpdatedAt         time.Time
}

ModelCall is the durable ledger row of one model invocation. Usage and cost are accumulated at settlement; content is never stored (prompt/completion stay out of kernel telemetry by policy).

type ModelCallStatus

type ModelCallStatus string

ModelCallStatus is the lifecycle of one model invocation.

const (
	ModelCallStarted   ModelCallStatus = "STARTED"
	ModelCallCompleted ModelCallStatus = "COMPLETED"
	ModelCallFailed    ModelCallStatus = "FAILED"
	ModelCallStopped   ModelCallStatus = "STOPPED"
)

func (ModelCallStatus) Terminal

func (s ModelCallStatus) Terminal() bool

type ModelDescriptor

type ModelDescriptor struct {
	ID                            uuid.UUID
	TenantID                      string
	Provider                      string
	ModelName                     string
	SupportsStreaming             bool
	InputPriceMicroUSDPerMillion  money.MicroUSD
	OutputPriceMicroUSDPerMillion money.MicroUSD
	PriceRevision                 string
	SpecHash                      [sha256.Size]byte
	CreatedAt                     time.Time
}

ModelDescriptor is a versioned declaration of a model capability and its price table. It is immutable per (tenant, provider, model): a price change registers a new price revision under the same identity.

func (ModelDescriptor) Ref

func (d ModelDescriptor) Ref() string

Ref returns the canonical provider/model reference.

func (ModelDescriptor) Validate

func (d ModelDescriptor) Validate() error

type ModelUsageCertainty

type ModelUsageCertainty string
const (
	ModelUsageKnownZero ModelUsageCertainty = "KNOWN_ZERO_USAGE"
	ModelUsageKnown     ModelUsageCertainty = "KNOWN_USAGE"
	ModelUsageUnknown   ModelUsageCertainty = "UNKNOWN_USAGE"
)

func (ModelUsageCertainty) Valid

func (c ModelUsageCertainty) Valid() bool

type OutboxEvent

type OutboxEvent struct {
	ID               uuid.UUID
	TenantID         string
	AggregateType    string
	AggregateID      uuid.UUID
	AggregateVersion int64
	EventType        string
	Payload          json.RawMessage
	OccurredAt       time.Time
	PublishAttempts  int
	LockedBy         string
	LockedUntil      time.Time
	LockFencingToken int64
}

type PackageSignature

type PackageSignature struct {
	KeyID          string // signing key identity in the trust registry
	Signature      string // base64 raw std ed25519 signature over the manifest digest
	ManifestDigest string // hex sha256 of the canonical signed manifest
}

PackageSignature is the verified signature envelope persisted with a publication (ADR-010). It is populated only when publish admission verified the signed Agent Package; all three fields are set together or none.

type PoolHealthStore

type PoolHealthStore interface {
	// PoolInstanceHealth reports whether each runtime instance is presumed
	// alive at now. An instance is unhealthy while it holds an unreleased
	// lease whose heartbeat is stale: the lease expired (expires_at <= now)
	// or was not renewed within the freshness window (heartbeat_at <= now -
	// freshness). An instance with no unreleased leases is healthy — idling
	// is not a failure signal. Every requested instance ID appears in the
	// result; callers treat an ID missing from the map as unhealthy
	// (fail-closed).
	PoolInstanceHealth(context.Context, []string, time.Time, time.Duration) (map[string]bool, error)
}

PoolHealthStore reports runtime instance liveness derived from lease heartbeats (v0.6): placement consults it before scheduling so that pools whose worker stopped renewing its lease are rejected instead of stranding a new attempt until lease-expiry recovery.

type PutMemoryInput

type PutMemoryInput struct {
	TenantID          string
	Namespace         string
	Key               string
	ContentType       string
	Content           string
	Embedding         []float32
	EmbeddingProvider string
	Sensitivity       string
	SourceTaskID      *uuid.UUID
	SourceRunID       *uuid.UUID
	SourceAttemptID   *uuid.UUID
	Provenance        json.RawMessage
	RetentionUntil    *time.Time
}

func (PutMemoryInput) Validate

func (in PutMemoryInput) Validate() error

type ReceiptStore

type ReceiptStore interface {
	GetRuntimeReceipt(context.Context, string, uuid.UUID, string, string) (RuntimeReceipt, error)
	WriteRuntimeReceipt(context.Context, WriteRuntimeReceiptInput) error
}

type RecoverExpiredAttemptInput

type RecoverExpiredAttemptInput struct {
	TenantID     string
	AttemptID    uuid.UUID
	FencingToken int64
	NewAttemptID uuid.UUID
	NewLeaseID   uuid.UUID
	LeaseTTL     time.Duration
	MaxAttempts  int
	// DeadlineExceeded terminally stops the task even if the worker lease is
	// still healthy. It must never create a retry attempt.
	DeadlineExceeded bool
}

type RecoveryCandidate

type RecoveryCandidate struct {
	TenantID         string
	AttemptID        uuid.UUID
	FencingToken     int64
	TaskSpec         json.RawMessage
	DeadlineExceeded bool
}

type RecoveryResult

type RecoveryResult struct {
	Retried bool
	Lease   AttemptLease
}

type RegisterModelDescriptorInput

type RegisterModelDescriptorInput struct {
	TenantID                      string
	Provider                      string
	ModelName                     string
	SupportsStreaming             bool
	InputPriceMicroUSDPerMillion  money.MicroUSD
	OutputPriceMicroUSDPerMillion money.MicroUSD
	PriceRevision                 string
}

func (RegisterModelDescriptorInput) ValidateAndHash

type RegisterToolDescriptorInput

type RegisterToolDescriptorInput struct {
	TenantID         string
	Name             string
	Version          string
	SideEffectRisk   ToolRisk
	Actions          []string
	ResourcePatterns []string
	ParamsSchema     json.RawMessage
}

func (RegisterToolDescriptorInput) ValidateAndHash

func (in RegisterToolDescriptorInput) ValidateAndHash() (ToolDescriptor, [sha256.Size]byte, error)

ValidateAndHash returns the normalized descriptor document and its digest.

type ReserveTaskUsageInput

type ReserveTaskUsageInput struct {
	TenantID       string
	TaskID         uuid.UUID
	ReservationKey string
	Amount         TaskBudget
	ExpiresAt      time.Time
}

func (ReserveTaskUsageInput) Valid

func (in ReserveTaskUsageInput) Valid() bool

type Run

type Run struct {
	ID                  uuid.UUID
	TenantID            string
	TaskID              uuid.UUID
	Ordinal             int
	Phase               domain.RunPhase
	ActiveAttemptID     *uuid.UUID
	CurrentFencingToken int64
	ResultRef           string
	ResourceVersion     int64
	CreatedAt           time.Time
	UpdatedAt           time.Time
	CompletedAt         *time.Time
}

type RunMailboxScope

type RunMailboxScope struct {
	TenantID string
	RunID    string
	TaskID   string
	// AgentVersionRef is the version reference of the run's task. A send that
	// pairs a run with any other version reference names a mailbox that no
	// attempt will ever drain.
	AgentVersionRef string
}

RunMailboxScope is the mailbox identity a run id resolves to. A mailbox is addressed by (agent version reference, run id), and the version reference is not a property of the run itself: it comes from the run's task, which is the immutable publication resolved during admission.

type RuntimeAssignment

type RuntimeAssignment struct {
	Task Task
	// AgentVersion is the immutable publication resolved during admission.
	// Runtime providers receive this declaration so adapter selection and
	// capability grants never come from mutable Task input.
	AgentVersion     *AgentVersion
	Run              Run
	Attempt          Attempt
	Lease            Lease
	ResumeCheckpoint *Checkpoint
	// PendingApprovalID is the approval a WAITING_APPROVAL attempt must
	// re-present to the Tool Gateway to resume execution.
	PendingApprovalID *uuid.UUID
}

type RuntimePolicy

type RuntimePolicy struct {
	SpawnGuards SpawnGuards
}

RuntimePolicy is the dynamic-orchestration policy the controller resolves from the workflow document at runtime.

func DecodeWorkflowRuntimePolicy

func DecodeWorkflowRuntimePolicy(spec json.RawMessage) RuntimePolicy

DecodeWorkflowRuntimePolicy extracts the runtime policy from a stored workflow document. Unknown documents yield the zero policy (dynamic spawn disabled).

type RuntimePoolOperatorStore

type RuntimePoolOperatorStore interface {
	UpdateRuntimePoolStatus(context.Context, UpdateRuntimePoolStatusInput) (RuntimePoolState, error)
}

type RuntimePoolState

type RuntimePoolState struct {
	ID              string `json:"id"`
	Status          string `json:"status"`
	ResourceVersion int64  `json:"resourceVersion"`
}

type RuntimeReceipt

type RuntimeReceipt struct {
	RequestHash [sha256.Size]byte
	Response    json.RawMessage
	ProcessedAt time.Time
}

RuntimeReceipt is the durable outcome record of one runtime operation.

type RuntimeStore

type RuntimeStore interface {
	KernelStore
	// WorkflowLineage resolves the workflow origin from the task's explicit
	// lineage columns; ok=false marks standalone tasks. The version is the
	// workflow's current resource version at read time.
	WorkflowLineage(context.Context, string, uuid.UUID) (workflowID uuid.UUID, stepName string, version int64, ok bool, err error)
	PollRuntimeAssignment(context.Context, string, string) (RuntimeAssignment, error)
	GetRuntimeAssignment(context.Context, string, uuid.UUID, int64) (RuntimeAssignment, error)
	GetHeartbeatStatus(context.Context, string, uuid.UUID, int64) (HeartbeatStatus, error)
	CommitCheckpoint(context.Context, CommitCheckpointInput) (Checkpoint, Attempt, error)
	CompleteAttempt(context.Context, CompleteAttemptInput) (CompleteAttemptResult, error)
	AcknowledgeCancellation(context.Context, CancelAttemptInput) (CancelAttemptResult, error)
	ListExpiredAttempts(context.Context, time.Time, int) ([]RecoveryCandidate, error)
	RecoverExpiredAttempt(context.Context, RecoverExpiredAttemptInput) (RecoveryResult, error)
}

type ScheduleTaskInput

type ScheduleTaskInput struct {
	TaskID              uuid.UUID
	TenantID            string
	OwnerID             string
	ClaimFencingToken   int64
	ExpectedTaskVersion int64
	RunID               uuid.UUID
	AttemptID           uuid.UUID
	LeaseID             uuid.UUID
	RuntimePoolID       string
	RuntimeClass        string
	RuntimeInstanceID   string
	LeaseTTL            time.Duration
	RequestedCPU        int64
	RequestedMemory     int64
	RequestedLLMSlots   int
}

type SearchMemoryInput

type SearchMemoryInput struct {
	TenantID    string
	Query       string
	Embedding   []float32
	Namespace   string
	Sensitivity string
	Limit       int
}

func (SearchMemoryInput) Validate

func (in SearchMemoryInput) Validate() error

type SetTenantQuotaInput

type SetTenantQuotaInput struct {
	TenantID      string
	WindowSeconds int64
	Limits        TaskBudget
}

SetTenantQuotaInput configures a tenant's aggregate consumption quota. WindowSeconds must be at least 60; limits must be non-negative.

func (SetTenantQuotaInput) Valid

func (in SetTenantQuotaInput) Valid() bool

type SettleTaskUsageDeltaInput

type SettleTaskUsageDeltaInput struct {
	TenantID string
	TaskID   uuid.UUID
	// FamilyPrefix scopes the already-settled sum (e.g. "model:<callID>").
	// Wildcards are rejected so the prefix can never widen the match.
	FamilyPrefix string
	// Target is the cumulative usage the family must reach.
	Target TaskBudget
	// IdempotencyKey is the key of the delta settlement row.
	IdempotencyKey string
	ReservationKey string
}

SettleTaskUsageDeltaInput settles a usage family up to a cumulative target: the delta between what the family already settled and the target is recorded under one idempotency key. The family is the set of settlements whose idempotency key is FamilyPrefix followed by ":<suffix>". This is the exact accounting primitive for model calls: per-step Settle records accrue under "model:<callID>:<seq>" and Finish settles only the remainder to reach the final cumulative total, so a stream that both settles steps and finalizes is charged exactly once.

func (SettleTaskUsageDeltaInput) Valid

func (in SettleTaskUsageDeltaInput) Valid() bool

type SettleTaskUsageInput

type SettleTaskUsageInput struct {
	TenantID       string
	TaskID         uuid.UUID
	IdempotencyKey string
	Usage          TaskBudget
	// ReservationKey identifies the active pre-consumption reservation that
	// this settlement replaces. It is excluded from concurrent headroom.
	ReservationKey string
}

func (SettleTaskUsageInput) Valid

func (in SettleTaskUsageInput) Valid() bool

type SpawnDenial

type SpawnDenial struct {
	Code    string
	Message string
}

SpawnDenial is a structured guard rejection: the brokered tool surfaces the stable code to the agent instead of a raw error string.

func (SpawnDenial) Error

func (d SpawnDenial) Error() string

func (SpawnDenial) Unwrap

func (d SpawnDenial) Unwrap() error

type SpawnGuards

type SpawnGuards struct {
	Enabled              bool
	MaxDynamicSteps      int64
	MaxChildrenPerStep   int64
	MaxSpawnDepth        int
	MaxWorkflowSteps     int64
	MaxSpawnTasks        int64
	MaxSpawnTokens       int64
	MaxSpawnCostMicroUSD money.MicroUSD
}

SpawnGuards carries the dynamic-orchestration runtime limits the spawning path enforces. Zero disables a guard.

type SpawnWorkflowStepInput

type SpawnWorkflowStepInput struct {
	WorkflowID      uuid.UUID
	TenantID        string
	WorkflowVersion int64
	ParentStepName  string
	Name            string
	Goal            string
	AgentVersionRef string
	Spec            json.RawMessage
	MaxAttempts     int
	Guards          SpawnGuards
	IdempotencyKey  string
	Arguments       json.RawMessage
}

SpawnWorkflowStepInput creates one dynamic step. SpawnKey is the brokered tool call's idempotency fingerprint: replaying the same spawn returns the existing step instead of creating a second one. The guards are the runtime policy resolved from the workflow document.

type SpawnWorkflowStepResult

type SpawnWorkflowStepResult struct {
	Step              WorkflowStep
	Workflow          Workflow
	WorkflowExhausted bool
	Created           bool
	Usage             WorkflowUsage
}

SpawnWorkflowStepResult reports the step (new or replayed), the workflow's budget ceilings, and the usage snapshot the guard evaluated against.

type StepStatus

type StepStatus string

StepStatus is the lifecycle of one workflow step.

const (
	StepPending         StepStatus = "PENDING"
	StepWaitingApproval StepStatus = "WAITING_APPROVAL"
	StepRunning         StepStatus = "RUNNING"
	StepSucceeded       StepStatus = "SUCCEEDED"
	StepFailed          StepStatus = "FAILED"
	StepSkipped         StepStatus = "SKIPPED"
	StepCancelled       StepStatus = "CANCELLED"
)

func (StepStatus) Terminal

func (s StepStatus) Terminal() bool

type Task

type Task struct {
	ID                  uuid.UUID
	TenantID            string
	Namespace           string
	AgentVersionRef     string
	AgentVersionID      *uuid.UUID
	Goal                string
	Spec                json.RawMessage
	RequestHash         [32]byte
	IdempotencyKey      string
	Phase               domain.TaskPhase
	AdmissionReasonCode string
	AdmittedAt          *time.Time
	CancelRequestedAt   *time.Time
	ActiveRunID         *uuid.UUID
	ResultRef           string
	WorkflowID          *uuid.UUID
	WorkflowStepID      *uuid.UUID
	WorkflowStepName    string
	WorkflowAttempt     int
	ParentTaskID        *uuid.UUID
	// ExecutionDeadlineAt is the hard stop computed when execution begins:
	// min(workload deadline, start + wallSeconds).
	ExecutionDeadlineAt *time.Time
	// NextScheduleAttemptAt gates scheduling-claim eligibility (O6): a task
	// deferred after a no-placement is not claimable by the scheduler until
	// this deadline. Nil means eligible immediately.
	NextScheduleAttemptAt *time.Time
	// ScheduleRetryCount is the number of consecutive no-placement
	// deferrals; it drives the exponential scheduling backoff and resets on
	// successful placement.
	ScheduleRetryCount    int64
	LastScheduleRejection json.RawMessage
	ResourceVersion       int64
	CreatedAt             time.Time
	UpdatedAt             time.Time
}

type TaskBudget

type TaskBudget struct {
	Tokens       int64
	CostMicroUSD money.MicroUSD
	ToolCalls    int64
	WallSeconds  int64
}

TaskBudget is the reserved or consumed four-dimensional budget of a task. All fields are non-negative; a zero budget means the dimension is unlimited.

func (TaskBudget) Valid

func (b TaskBudget) Valid() bool

func (TaskBudget) Zero

func (b TaskBudget) Zero() bool

type TaskBudgetStatus

type TaskBudgetStatus struct {
	TaskID          uuid.UUID
	TenantID        string
	Reserved        TaskBudget
	Consumed        TaskBudget
	Exhausted       bool
	ResourceVersion int64
	UpdatedAt       time.Time
}

TaskBudgetStatus is the current reservation and cumulative consumption of a task, as derived from the append-only settlement ledger.

type TaskCancellationStore

type TaskCancellationStore interface {
	RequestTaskCancellation(context.Context, string, uuid.UUID, int64) (Task, error)
}

type TaskClaim

type TaskClaim struct {
	Task         Task
	Kind         ControllerKind
	OwnerID      string
	FencingToken int64
	ExpiresAt    time.Time
}

type TenantQuota

type TenantQuota struct {
	TenantID        string
	WindowSeconds   int64
	Limits          TaskBudget
	ResourceVersion int64
	UpdatedAt       time.Time
}

TenantQuota is a tenant's windowed aggregate consumption limits. A zero dimension means that dimension is unlimited, matching task budget semantics; a tenant without a quota row is never gated.

type TenantQuotaStore

type TenantQuotaStore interface {
	// SetTenantQuota configures or replaces the tenant's quota. Existing
	// window consumption is preserved; only the limits and window length
	// change.
	SetTenantQuota(context.Context, SetTenantQuotaInput) (TenantQuota, error)
	// GetTenantQuota returns the tenant's configured quota or ErrNotFound.
	GetTenantQuota(context.Context, string) (TenantQuota, error)
	// DeleteTenantQuota removes the tenant's quota configuration. Window
	// consumption rows become inert; future admissions are unlimited until a
	// new quota is configured.
	DeleteTenantQuota(context.Context, string) error
	// GetTenantQuotaUsage returns the consumption of the window containing at.
	GetTenantQuotaUsage(context.Context, string, time.Time) (TenantWindowUsage, error)
}

TenantQuotaStore is the persistence contract for tenant aggregate consumption quotas. GetTenantQuota reports ErrNotFound for a tenant without a configured quota; GetTenantQuotaUsage reports the current window's consumption (zero usage when the tenant settled nothing in it yet) or ErrNotFound when no quota is configured.

type TenantWindowUsage

type TenantWindowUsage struct {
	TenantID        string
	WindowStart     time.Time
	Consumed        TaskBudget
	Reserved        TaskBudget
	ResourceVersion int64
	UpdatedAt       time.Time
}

TenantWindowUsage is the settled and reserved aggregate consumption of one tenant in one fixed window (v0.8: reservation holds the ceilings of admitted-but-not-terminal tasks).

type ToolApproval

type ToolApproval struct {
	ID              uuid.UUID
	TenantID        string
	CallID          uuid.UUID
	TaskID          uuid.UUID
	RunID           uuid.UUID
	AttemptID       uuid.UUID
	ToolName        string
	ToolVersion     string
	Action          string
	Resource        string
	ArgsHash        [sha256.Size]byte
	Status          ToolApprovalStatus
	RequestedAt     time.Time
	ExpiresAt       time.Time
	DecidedAt       *time.Time
	DecidedBy       string
	ResourceVersion int64
}

ToolApproval is a human authorization bound to a canonical call summary.

type ToolApprovalStatus

type ToolApprovalStatus string

ToolApprovalStatus is the lifecycle of one approval request.

const (
	ToolApprovalPending  ToolApprovalStatus = "PENDING"
	ToolApprovalApproved ToolApprovalStatus = "APPROVED"
	ToolApprovalRejected ToolApprovalStatus = "REJECTED"
	ToolApprovalExpired  ToolApprovalStatus = "EXPIRED"
)

type ToolCall

type ToolCall struct {
	ID              uuid.UUID
	TenantID        string
	TaskID          uuid.UUID
	RunID           uuid.UUID
	AttemptID       uuid.UUID
	ToolName        string
	ToolVersion     string
	Action          string
	Resource        string
	ArgsHash        [sha256.Size]byte
	Status          ToolCallStatus
	DecisionReasons []string
	PolicyRevision  string
	ApprovalID      *uuid.UUID
	IdempotencyKey  string
	RequestHash     [sha256.Size]byte
	ResourceVersion int64
	CreatedAt       time.Time
	UpdatedAt       time.Time
}

ToolCall is the durable decision record of one invocation, bound to taskId + runId + attemptId + idempotencyKey (invariant 6).

type ToolCallStatus

type ToolCallStatus string

ToolCallStatus is the decision ledger status of one invocation.

const (
	ToolCallPending          ToolCallStatus = "PENDING"
	ToolCallRequiresApproval ToolCallStatus = "REQUIRES_APPROVAL"
	ToolCallApproved         ToolCallStatus = "APPROVED"
	ToolCallExecuted         ToolCallStatus = "EXECUTED"
	ToolCallDenied           ToolCallStatus = "DENIED"
	ToolCallFailed           ToolCallStatus = "FAILED"
)

type ToolDescriptor

type ToolDescriptor struct {
	ID               uuid.UUID
	TenantID         string
	Name             string
	Version          string
	SideEffectRisk   ToolRisk
	Actions          []string
	ResourcePatterns []string
	ParamsSchema     json.RawMessage
	SpecHash         [sha256.Size]byte
	CreatedAt        time.Time
}

ToolDescriptor is a versioned declaration of an external capability. A descriptor is immutable per (tenant, name, version): a change is a new version.

func (ToolDescriptor) Validate

func (d ToolDescriptor) Validate() error

Validate checks the structural bounds of a descriptor. ParamsSchema must be valid JSON and bounded; semantic schema validation happens at invocation time in the tool domain.

type ToolRisk

type ToolRisk string

ToolRisk classifies the side-effect surface of a tool. High-risk tools require human approval before execution.

const (
	ToolRiskNone ToolRisk = "none"
	ToolRiskLow  ToolRisk = "low"
	ToolRiskHigh ToolRisk = "high"
)

func (ToolRisk) Valid

func (r ToolRisk) Valid() bool

type TransitionAttemptInput

type TransitionAttemptInput struct {
	TenantID               string
	AttemptID              uuid.UUID
	FencingToken           int64
	ExpectedAttemptVersion int64
	To                     domain.AttemptPhase
	FailureCode            string
	FailureMessage         string
}

type TransitionWorkflowInput

type TransitionWorkflowInput struct {
	TenantID        string
	WorkflowID      uuid.UUID
	ExpectedVersion int64
	To              WorkflowStatus
	FailureCode     string
	ExpectedOwner   string
}

TransitionWorkflowInput CAS-transitions one workflow. ExpectedOwner, when non-empty, fences the transition to the orchestrator instance that holds a live claim: the write fails with ErrFenced when the claim was lost or expired. Empty disables the check (single-instance mode, non-claiming controllers).

type TransitionWorkflowStepInput

type TransitionWorkflowStepInput struct {
	TenantID        string
	WorkflowID      uuid.UUID
	StepName        string
	ExpectedVersion int64
	To              StepStatus
	TaskID          *uuid.UUID
	AttemptCount    *int
	ResultSummary   json.RawMessage
	FailureCode     string
	ExpectedOwner   string
}

TransitionWorkflowStepInput CAS-transitions one step. Zero fields are left unchanged; TaskID/AttemptCount set when provided. ExpectedOwner, when non-empty, fences the transition to the orchestrator instance that holds a live claim on the parent workflow (see TransitionWorkflowInput).

type UpdateRuntimePoolStatusInput

type UpdateRuntimePoolStatusInput struct {
	TenantID string
	PoolID   string
	Status   string
	// OperatorSubject is the authenticated principal requesting the status
	// change. It must hold a runtime_pool_operator_grants row for the pool;
	// the tenant usage grant alone is never sufficient.
	OperatorSubject string
	ExpectedVersion int64
}

type UpdateToolCallInput

type UpdateToolCallInput struct {
	TenantID        string
	ToolCallID      uuid.UUID
	ExpectedVersion int64
	Status          ToolCallStatus
	DecisionReasons []string
	PolicyRevision  string
	ApprovalID      *uuid.UUID
}

type Workflow

type Workflow struct {
	ID                uuid.UUID
	TenantID          string
	Namespace         string
	IdempotencyKey    string
	Goal              string
	Spec              json.RawMessage
	Status            WorkflowStatus
	FailureCode       string
	CancelRequestedAt *time.Time
	// Budget ceilings. Zero means the dimension is unbounded.
	BudgetMaxTasks        int64
	BudgetMaxTokens       int64
	BudgetMaxCostMicroUSD money.MicroUSD
	BudgetExhaustedAt     *time.Time
	DeadlineAt            *time.Time
	DeadlineExceededAt    *time.Time
	// NeedsBudgetReconciliation is set when a step's token/cost reservation may
	// be understated relative to its derived task spec — e.g. after the 000028
	// upgrade backfilled task-count slots but could not re-derive merged specs
	// in pure SQL. While set, dynamic spawning is paused (a stale-low commitment
	// could slip a spawn past a ceiling); the controller's reconcile loop
	// re-derives the reservations and clears the flag.
	NeedsBudgetReconciliation bool
	ResourceVersion           int64
	CreatedAt                 time.Time
	UpdatedAt                 time.Time
}

Workflow is one durable workflow run.

type WorkflowStatus

type WorkflowStatus string

WorkflowStatus is the lifecycle of one workflow run.

const (
	WorkflowPending   WorkflowStatus = "PENDING"
	WorkflowRunning   WorkflowStatus = "RUNNING"
	WorkflowSucceeded WorkflowStatus = "SUCCEEDED"
	WorkflowFailed    WorkflowStatus = "FAILED"
	WorkflowCancelled WorkflowStatus = "CANCELLED"
)

func (WorkflowStatus) Terminal

func (s WorkflowStatus) Terminal() bool

type WorkflowStep

type WorkflowStep struct {
	ID               uuid.UUID
	TenantID         string
	WorkflowID       uuid.UUID
	Name             string
	Ordinal          int
	Status           StepStatus
	AttemptCount     int
	TaskID           *uuid.UUID
	ResultSummary    json.RawMessage
	FailureCode      string
	DecidedBy        string
	ApprovalDecision string
	DecidedAt        *time.Time
	ParentStepName   string
	SpawnDepth       int
	IsDynamic        bool
	SpawnKey         string
	Goal             string
	AgentVersionRef  string
	Spec             json.RawMessage
	MaxAttempts      int
	// Reserved* is the outstanding workflow budget reservation held by an
	// undispatched or retrying step: the future Task's token/cost ceiling
	// plus its task-count slot. It transfers to the task's own budget
	// ledger at admission and returns to zero when the step reaches a
	// terminal state without one.
	ReservedTasks        int64
	ReservedTokens       int64
	ReservedCostMicroUSD money.MicroUSD
	ResourceVersion      int64
	CreatedAt            time.Time
	UpdatedAt            time.Time
}

WorkflowStep is one step of a workflow: a declared DAG node plus its dispatch state. AttemptCount drives the single-step retry budget. Dynamic Dynamic steps carry their whole definition here — declared steps keep theirs in the workflow document — with the spawning parent and depth lineage for the recursion guard.

type WorkflowStore

type WorkflowStore interface {
	CreateWorkflow(context.Context, CreateWorkflowInput) (CreateWorkflowResult, error)
	GetWorkflow(context.Context, string, uuid.UUID) (Workflow, error)
	// ListActiveWorkflows returns non-terminal workflows oldest-first for
	// the orchestrator reconcile loop (all tenants; creation is where
	// tenant scoping is enforced).
	ListActiveWorkflows(context.Context, int) ([]Workflow, error)
	ListWorkflowSteps(context.Context, string, uuid.UUID) ([]WorkflowStep, error)
	GetWorkflowStep(context.Context, string, uuid.UUID, string) (WorkflowStep, error)
	TransitionWorkflow(context.Context, TransitionWorkflowInput) (Workflow, error)
	TransitionWorkflowStep(context.Context, TransitionWorkflowStepInput) (WorkflowStep, error)
	DecideWorkflowStepApproval(context.Context, DecideWorkflowStepApprovalInput) (WorkflowStep, error)
	// RequestWorkflowCancellation records the durable cancellation intent;
	// the orchestrator propagates it to active steps and finalizes.
	RequestWorkflowCancellation(context.Context, string, uuid.UUID, int64) (Workflow, error)
	// ArtifactMetadata reads the digest, size and media type of one stored
	// artifact URI so the orchestrator can open task result documents.
	ArtifactMetadata(context.Context, string, string) ([]byte, int64, string, error)
	// ClaimWorkflows leases active workflows to one orchestrator instance
	// Expired claims are stolen, so a dead instance's workflows are
	// taken over by its peers. Tenants are claimed round-robin.
	ClaimWorkflows(context.Context, ClaimWorkflowsInput) ([]Workflow, error)
	// SpawnWorkflowStep creates one dynamic step with all recursion, fan-out
	// and budget guards applied in the same transaction. A spawn_key
	// replay returns the existing step.
	SpawnWorkflowStep(context.Context, SpawnWorkflowStepInput) (SpawnWorkflowStepResult, error)
	// MarkWorkflowBudgetExhausted records the durable budget-stop intent.
	MarkWorkflowBudgetExhausted(context.Context, string, uuid.UUID, int64) (Workflow, error)
	// MarkWorkflowDeadlineExceeded records the durable deadline-stop intent.
	MarkWorkflowDeadlineExceeded(context.Context, string, uuid.UUID, int64) (Workflow, error)
	// WorkflowUsageSnapshot aggregates a workflow's task count and settled
	// usage.
	WorkflowUsageSnapshot(context.Context, string, uuid.UUID) (WorkflowUsage, error)
}

WorkflowStore is the durable workflow surface. The postgres Store satisfies it.

type WorkflowUsage

type WorkflowUsage struct {
	Tasks                 int64
	Tokens                int64
	CostMicroUSD          money.MicroUSD
	ReservedTokens        int64
	ReservedCostMicroUSD  money.MicroUSD
	PendingOverage        bool
	BudgetMaxTasks        int64
	BudgetMaxTokens       int64
	BudgetMaxCostMicroUSD money.MicroUSD
	// StepReserved* counts the workflow budget reservations still held by
	// undispatched (or retrying) steps: the outstanding future commitment
	// that exists before any task budget ledger does.
	StepReservedTasks        int64
	StepReservedTokens       int64
	StepReservedCostMicroUSD money.MicroUSD
}

WorkflowUsage is the aggregated consumption of one workflow: tasks that carry its idempotency prefix plus their settled usage.

func (WorkflowUsage) CommittedCostMicroUSD

func (u WorkflowUsage) CommittedCostMicroUSD() money.MicroUSD

CommittedCostMicroUSD returns settled plus task-reserved plus step-reserved cost: the workflow's total cost commitment.

func (WorkflowUsage) CommittedTasks

func (u WorkflowUsage) CommittedTasks() int64

CommittedTasks returns the workflow's total task promise: created tasks plus the task slots reserved by undispatched steps.

func (WorkflowUsage) CommittedTokens

func (u WorkflowUsage) CommittedTokens() int64

CommittedTokens returns settled plus task-reserved plus step-reserved tokens: the workflow's total token commitment.

func (WorkflowUsage) Exhausted

func (u WorkflowUsage) Exhausted() bool

Exhausted reports whether any declared ceiling is met or exceeded by created tasks and their settled or task-reserved usage. Step reservations are excluded: a promise that exactly fills the budget must still run, and over-promising is already impossible because spawn and creation reserve inside their transactions.

type WriteRuntimeReceiptInput

type WriteRuntimeReceiptInput struct {
	TenantID       string
	AttemptID      uuid.UUID
	Operation      string
	IdempotencyKey string
	RequestHash    [sha256.Size]byte
	Response       json.RawMessage
}

Directories

Path Synopsis
Package postgres implements the Fenced kernel persistence contract on PostgreSQL.
Package postgres implements the Fenced kernel persistence contract on PostgreSQL.

Jump to

Keyboard shortcuts

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