Documentation
¶
Overview ¶
Package delegation defines the canonical durable contracts for Secure Task Delegation (B32): logical task delegation, messages/parts, terminal results, transferable artifact references (schema only), ordered task events, idempotency, content digests, and a pluggable Store interface.
T01 delivers the schemas, validation, transitions, and store interface. T02 adds snapshot-based two-sided authorization. T03 wires the SDK and gateway. T04 implements the artifact broker. T05 delivers event-driven wait/wake. T06 is the adversary gate.
Index ¶
- Constants
- Variables
- func AllErrorCodes() []string
- func CanonicalJSON(v interface{}) ([]byte, error)
- func CanonicalMessagePartsDigest(parts []MessagePart) (string, error)
- func CanonicalResultDigest(r *Result) (string, error)
- func ComputeSnapshotDigest(s *CommunicationSnapshot) (string, error)
- func DeriveCapabilityTokenForTest(expect BindingExpectation) string
- func GenerateCapabilityToken() (string, error)
- func Sha256Hex(data []byte) string
- func ValidErrorCode(code string) bool
- func ValidateIDPrefix(id, prefix string) bool
- func ValidateMessage(m *Message) error
- func ValidateResult(r *Result) error
- func ValidateSystemRole(role MessageRole, writer WriterKind) error
- func ValidateTask(t *Task) error
- func ValidateTaskEvent(ev *TaskEvent) error
- func ValidateTaskTransition(from, to TaskStatus) error
- func ValidateTaskTransitionString(from, to string) error
- func ValidateTransferableArtifactRef(ref *TransferableArtifactRef) error
- type ArtifactBroker
- type AuthorizeRequest
- type AuthzAuditRecord
- type AuthzDecision
- type BindingExpectation
- type CalleeIngressRule
- type CalleeRef
- type CallerRef
- type Classification
- type CommitReq
- type CommunicationSnapshot
- type EventID
- type EventType
- type FileArtifactBroker
- func (b *FileArtifactBroker) AuthorizeRead(ctx context.Context, artifactID, consumerLogicalID, workflowID string, ...) error
- func (b *FileArtifactBroker) Commit(ctx context.Context, req CommitReq) (TransferableArtifactRef, error)
- func (b *FileArtifactBroker) ProjectReadOnly(ctx context.Context, artifactID, consumerLogicalID string, now time.Time) (ProjectedArtifact, error)
- func (b *FileArtifactBroker) VerifyDigest(ctx context.Context, artifactID string) error
- type GatewayEnforcer
- type MemoryStore
- func (s *MemoryStore) AppendEvent(ctx context.Context, ev TaskEvent) (int64, error)
- func (s *MemoryStore) AppendMessage(ctx context.Context, msg Message) error
- func (s *MemoryStore) CASTask(ctx context.Context, t Task, expectedGen int64) error
- func (s *MemoryStore) CreateTask(ctx context.Context, t Task) error
- func (s *MemoryStore) GetResult(ctx context.Context, taskID TaskID) (*Result, error)
- func (s *MemoryStore) GetTask(ctx context.Context, taskID TaskID) (*Task, error)
- func (s *MemoryStore) GetTaskByIdempotencyKey(ctx context.Context, callerIdentity, idempotencyKeyStr string) (*Task, error)
- func (s *MemoryStore) ListEvents(ctx context.Context, taskID TaskID, afterSeq int64) ([]TaskEvent, error)
- func (s *MemoryStore) ListMessages(ctx context.Context, taskID TaskID, afterSeq int64) ([]Message, error)
- func (s *MemoryStore) PutResult(ctx context.Context, r Result) error
- func (s *MemoryStore) SubscribeEvents(ctx context.Context, taskID TaskID, afterSeq int64) (<-chan TaskEvent, func(), error)
- type MemoryStoreOption
- type Message
- type MessageID
- type MessagePart
- type MessageRole
- type PartKind
- type ProjectedArtifact
- type Result
- type ResultID
- type SideDecision
- type Store
- type Task
- type TaskEvent
- type TaskID
- type TaskOutbox
- type TaskStatus
- type TaskWaiter
- type TransferableArtifactRef
- type TransitionError
- type UsageSummary
- type ValidationError
- type WorkflowDelegationBinding
- type WriterKind
Constants ¶
const ( PrefixTask = "task-" PrefixMessage = "msg-" PrefixResult = "tres-" PrefixEvent = "tevt-" )
ID prefixes.
const ( DenyCallerBinding = "DENY_CALLER_BINDING" DenyCalleePolicy = "DENY_CALLEE_POLICY" DenyUnpromoted = "DENY_UNPROMOTED" DenySnapshotMismatch = "DENY_SNAPSHOT_MISMATCH" DenyExpired = "DENY_EXPIRED" DenyBudget = "DENY_BUDGET" ErrIdempotencyConflict = "ERR_IDEMPOTENCY_CONFLICT" ErrSequenceGap = "ERR_SEQUENCE_GAP" ErrInvalidMessage = "ERR_INVALID_MESSAGE" ErrForbiddenContent = "ERR_FORBIDDEN_CONTENT" )
const CapabilityHeader = "X-AgentPaaS-Capability"
CapabilityHeader is the internal HTTP/gRPC header name used to carry the per-binding capability token between the caller gateway and callee gateway. This header is STRIPPED before it reaches agent code and MUST NEVER appear in agent-facing responses, SDK DTOs, logs, or audit event payloads that are exposed beyond the gateway.
const CurrentSchemaVersion = "0.3.0"
CurrentSchemaVersion is the current schema version for delegation records.
Variables ¶
var ( ErrArtifactNotFound = errors.New("delegation: artifact not found") ErrArtifactAudienceDenied = errors.New("delegation: consumer not in audience") ErrArtifactExpired = errors.New("delegation: artifact expired") ErrArtifactDigestMismatch = errors.New("delegation: digest mismatch") ErrArtifactSizeExceeded = errors.New("delegation: artifact exceeds max bytes") ErrArtifactInvalidPath = errors.New("delegation: invalid artifact path") ErrArtifactSymlink = errors.New("delegation: symlink rejected") ErrArtifactHardlink = errors.New("delegation: hard link rejected") ErrArtifactWorkflowMismatch = errors.New("delegation: workflow mismatch") )
var TaskTransitions = map[TaskStatus]map[TaskStatus]bool{ TaskStatusPending: { TaskStatusAdmitted: true, TaskStatusDenied: true, TaskStatusCancelled: true, TaskStatusExpired: true, }, TaskStatusAdmitted: { TaskStatusRunning: true, TaskStatusCancelled: true, TaskStatusExpired: true, TaskStatusDenied: true, }, TaskStatusRunning: { TaskStatusSucceeded: true, TaskStatusFailed: true, TaskStatusCancelled: true, TaskStatusExpired: true, }, TaskStatusSucceeded: {}, TaskStatusFailed: {}, TaskStatusCancelled: {}, TaskStatusExpired: {}, TaskStatusDenied: {}, }
TaskTransitions defines legal TaskStatus transitions.
Functions ¶
func AllErrorCodes ¶
func AllErrorCodes() []string
AllErrorCodes returns all known stable error/denial codes.
func CanonicalJSON ¶
CanonicalJSON returns the canonical JSON bytes for any value (sorted keys, no trailing whitespace). Used for deterministic digests.
func CanonicalMessagePartsDigest ¶
func CanonicalMessagePartsDigest(parts []MessagePart) (string, error)
CanonicalMessagePartsDigest returns the SHA-256 hex digest of the canonical JSON representation of the message parts. Parts are sorted by kind, then text, for deterministic output.
func CanonicalResultDigest ¶
CanonicalResultDigest returns the SHA-256 hex digest of the canonical JSON representation of a Result struct (excluding the digest field itself).
func ComputeSnapshotDigest ¶
func ComputeSnapshotDigest(s *CommunicationSnapshot) (string, error)
ComputeSnapshotDigest produces a deterministic SHA-256 hex digest over the canonical JSON of the snapshot (excluding the SnapshotDigest field itself). Bindings are sorted by BindingID for deterministic output.
func DeriveCapabilityTokenForTest ¶
func DeriveCapabilityTokenForTest(expect BindingExpectation) string
DeriveCapabilityTokenForTest derives a deterministic capability token from a BindingExpectation. This is for tests only — production MUST use randomly generated tokens from GenerateCapabilityToken stored in BindingCapabilities.
func GenerateCapabilityToken ¶
GenerateCapabilityToken produces a cryptographically random unguessable capability token. This is called by the trusted harness/gateway at invoke bootstrap; the resulting token is stored in BindingCapabilities and NEVER serialized into agent responses.
func ValidErrorCode ¶
ValidErrorCode returns true if code is a known stable error/denial code.
func ValidateIDPrefix ¶
ValidateIDPrefix returns true if id is non-empty and starts with prefix.
func ValidateMessage ¶
ValidateMessage validates a Message envelope. Rejects control chars, secret sentinels, oversized parts, forbidden content, and endpoint-like fields.
func ValidateSystemRole ¶
func ValidateSystemRole(role MessageRole, writer WriterKind) error
ValidateSystemRole returns an error if the role is system and the writer is not a trusted runtime.
func ValidateTaskEvent ¶
ValidateTaskEvent performs lightweight validation on a TaskEvent.
func ValidateTaskTransition ¶
func ValidateTaskTransition(from, to TaskStatus) error
ValidateTaskTransition validates that a TaskStatus transition is legal. Returns nil if valid, or a *TransitionError if invalid.
func ValidateTaskTransitionString ¶
ValidateTaskTransitionString validates a task transition by string names. This is a convenience for tests and API layers.
func ValidateTransferableArtifactRef ¶
func ValidateTransferableArtifactRef(ref *TransferableArtifactRef) error
ValidateTransferableArtifactRef validates a TransferableArtifactRef.
Types ¶
type ArtifactBroker ¶
type ArtifactBroker interface {
// Commit writes the artifact blob, records metadata, and returns an
// immutable TransferableArtifactRef.
Commit(ctx context.Context, req CommitReq) (TransferableArtifactRef, error)
// AuthorizeRead checks that consumerLogicalID is in the artifact's
// audience, the workflow matches, and the ref has not expired.
AuthorizeRead(ctx context.Context, artifactID, consumerLogicalID, workflowID string, now time.Time) error
// ProjectReadOnly verifies digest, audience, expiry, and returns a
// ProjectedArtifact with a read-only host path under the broker store.
ProjectReadOnly(ctx context.Context, artifactID, consumerLogicalID string, now time.Time) (ProjectedArtifact, error)
// VerifyDigest re-hashes the blob and compares against the recorded digest.
VerifyDigest(ctx context.Context, artifactID string) error
}
ArtifactBroker manages digest-bound, audience-scoped artifact transfer. Committed artifacts are immutable; consumers receive read-only projected paths after authorization.
type AuthorizeRequest ¶
type AuthorizeRequest struct {
Snapshot *CommunicationSnapshot
BindingID string
Operation string
// Caller's live identity (must match snapshot caller pin).
CallerDeploymentID string
CallerPackageDigest string
// Requested callee (must match binding pin).
CalleePackageName string
CalleePackageVersion string
CalleeBundleDigest string
DataClass string
// CalleeIngressAllow is the callee's ingress policy from its package/deployment.
CalleeIngressAllow []CalleeIngressRule
// PromotedLookup is an optional hook: if set and returns false, DENY_UNPROMOTED.
PromotedLookup func(packageName, version, digest string) (bool, error)
// ExpectedSnapshotGeneration is the snapshot generation the caller
// asserts. When non-zero, AuthorizeDelegation rejects with
// DENY_SNAPSHOT_MISMATCH if it doesn't match the snapshot. Zero
// value means "not enforced" (backward compat for tests that don't
// set it).
ExpectedSnapshotGeneration int64
Now time.Time
}
AuthorizeRequest carries all information needed for two-sided authorization.
type AuthzAuditRecord ¶
type AuthzAuditRecord struct {
TaskID string `json:"task_id"`
WorkflowID string `json:"workflow_id"`
SnapshotGeneration int64 `json:"snapshot_generation"`
SnapshotDigest string `json:"snapshot_digest"`
BindingID string `json:"binding_id"`
CallerDecision SideDecision `json:"caller_decision"`
CalleeDecision SideDecision `json:"callee_decision"`
DenialCode string `json:"denial_code"`
DecidedAt time.Time `json:"decided_at"`
}
AuthzAuditRecord is a pure-data record of an authorization decision. Suitable for writing to the audit log.
func NewAuthzAuditRecord ¶
func NewAuthzAuditRecord( taskID, workflowID string, snapshotGeneration int64, snapshotDigest string, bindingID string, decision AuthzDecision, ) AuthzAuditRecord
NewAuthzAuditRecord creates an audit record from an authorization decision.
type AuthzDecision ¶
type AuthzDecision struct {
Allowed bool `json:"allowed"`
CallerDecision SideDecision `json:"caller_decision"`
CalleeDecision SideDecision `json:"callee_decision"`
DenialCode string `json:"denial_code,omitempty"`
Binding *WorkflowDelegationBinding `json:"binding,omitempty"`
}
AuthzDecision is the result of a two-sided authorization evaluation.
func AuthorizeDelegation ¶
func AuthorizeDelegation(req *AuthorizeRequest) AuthzDecision
AuthorizeDelegation performs two-sided authorization: 1. Caller side: snapshot must name the binding + match caller/callee pins. 2. Callee side: ingress policy must allow the caller + binding. Both sides are always evaluated when possible. DenialCode prefers caller code if caller failed, else callee code.
func AuthorizeDelegationWithPromotion ¶
func AuthorizeDelegationWithPromotion( req *AuthorizeRequest, lookup func(packageName, version, digest string) (bool, error), ) AuthzDecision
AuthorizeDelegationWithPromotion is a convenience wrapper that binds a PromotedLookup to AuthorizeRequest and calls AuthorizeDelegation.
type BindingExpectation ¶
type BindingExpectation struct {
BindingID string
WorkflowID string
CallerLease string
CalleeLease string
}
BindingExpectation is the set of claims that the callee gateway validates against the capability token.
type CalleeIngressRule ¶
type CalleeIngressRule struct {
CallerPackageName string `json:"caller_package_name"`
CallerPackageDigest string `json:"caller_package_digest,omitempty"`
AllowedBindings []string `json:"allowed_bindings"`
MaxDataClass string `json:"max_data_class"`
}
CalleeIngressRule defines who may call a callee.
type CalleeRef ¶
type CalleeRef struct {
DeploymentID string `json:"deployment_id,omitempty"` // resolved at admission; empty for unresolved logical pin
PackageName string `json:"package_name"`
PackageVersion string `json:"package_version"`
PackageDigest string `json:"package_digest"`
}
CalleeRef identifies the callee of a task.
type CallerRef ¶
type CallerRef struct {
DeploymentID string `json:"deployment_id"`
RunID string `json:"run_id"`
AttemptID string `json:"attempt_id"`
PackageName string `json:"package_name"`
PackageDigest string `json:"package_digest"`
}
CallerRef identifies the caller of a task.
type Classification ¶
type Classification string
Classification represents the data sensitivity level.
const ( ClassificationPublic Classification = "public" ClassificationInternal Classification = "internal" ClassificationConfidential Classification = "confidential" ClassificationRestricted Classification = "restricted" )
func AllClassifications ¶
func AllClassifications() []Classification
AllClassifications returns all valid Classification values in order.
func (Classification) Valid ¶
func (c Classification) Valid() bool
Valid returns true if c is a known Classification.
type CommitReq ¶
type CommitReq struct {
WorkflowID string
ProducerRunID string
ProducerAttemptID string
ProducerTaskID string
LogicalRef string
MediaType string
Classification Classification
Audience []string
ExpiresAt time.Time
// Reader is the source data. May be nil (error). Read up to MaxBytes.
Reader io.Reader
MaxBytes int64
}
CommitReq describes an artifact to commit.
type CommunicationSnapshot ¶
type CommunicationSnapshot struct {
SchemaVersion string `json:"schema_version"`
SnapshotGeneration int64 `json:"snapshot_generation"`
WorkflowID string `json:"workflow_id"`
TenantID string `json:"tenant_id"`
CallerDeploymentID string `json:"caller_deployment_id"`
CallerPackageName string `json:"caller_package_name"`
CallerPackageDigest string `json:"caller_package_digest"`
Bindings []WorkflowDelegationBinding `json:"bindings"`
SnapshotDigest string `json:"snapshot_digest,omitempty"`
}
CommunicationSnapshot is the immutable, signed pin used at task admission. It binds a caller identity to a set of delegation bindings. The SnapshotDigest covers the caller identity, workflow, tenant, generation, and all bindings via canonical JSON.
type EventID ¶
type EventID string
EventID identifies a task event.
func NewEventID ¶
NewEventID generates a cryptographically random event ID.
type EventType ¶
type EventType string
EventType represents the type of a task event.
const ( EventTaskAdmitted EventType = "TASK_ADMITTED" EventTaskDenied EventType = "TASK_DENIED" EventTaskStarted EventType = "TASK_STARTED" EventTaskMessage EventType = "TASK_MESSAGE" EventTaskProgress EventType = "TASK_PROGRESS" EventTaskSucceeded EventType = "TASK_SUCCEEDED" EventTaskFailed EventType = "TASK_FAILED" EventTaskCancelled EventType = "TASK_CANCELLED" EventTaskExpired EventType = "TASK_EXPIRED" EventArtifactCommitted EventType = "ARTIFACT_COMMITTED" )
func AllEventTypes ¶
func AllEventTypes() []EventType
AllEventTypes returns all valid EventType values.
func (EventType) MarshalJSON ¶
MarshalJSON implements json.Marshaler.
func (*EventType) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler.
type FileArtifactBroker ¶
type FileArtifactBroker struct {
// contains filtered or unexported fields
}
FileArtifactBroker stores artifacts on a local filesystem under a root.
func NewFileArtifactBroker ¶
func NewFileArtifactBroker(rootPath string) (*FileArtifactBroker, error)
NewFileArtifactBroker creates a broker rooted at rootPath.
func (*FileArtifactBroker) AuthorizeRead ¶
func (b *FileArtifactBroker) AuthorizeRead(ctx context.Context, artifactID, consumerLogicalID, workflowID string, now time.Time) error
AuthorizeRead checks authorization.
func (*FileArtifactBroker) Commit ¶
func (b *FileArtifactBroker) Commit(ctx context.Context, req CommitReq) (TransferableArtifactRef, error)
Commit writes the artifact and returns its ref.
func (*FileArtifactBroker) ProjectReadOnly ¶
func (b *FileArtifactBroker) ProjectReadOnly(ctx context.Context, artifactID, consumerLogicalID string, now time.Time) (ProjectedArtifact, error)
ProjectReadOnly returns a read-only artifact projection.
func (*FileArtifactBroker) VerifyDigest ¶
func (b *FileArtifactBroker) VerifyDigest(ctx context.Context, artifactID string) error
VerifyDigest re-hashes the blob and compares to the stored digest.
type GatewayEnforcer ¶
type GatewayEnforcer struct{}
GatewayEnforcer is the trusted component that attaches, validates, and strips per-binding capability tokens. Agent code never sees the token or the network alias.
In production, the full implementation maps capability tokens to binding state inside the gateway mesh. For T03, this is a thin stub that records enforcement points — every test path through ValidateAndStrip proves that the enforcement step was called and that token material is stripped.
func (*GatewayEnforcer) Attach ¶
func (g *GatewayEnforcer) Attach(token string) map[string]string
Attach returns headers for the trusted caller-gateway path. The returned map contains the CapabilityHeader key with the token as its value. This MUST only be called by the trusted caller gateway — never by agent code.
func (*GatewayEnforcer) ValidateAndStrip ¶
func (g *GatewayEnforcer) ValidateAndStrip(headers map[string]string, expectedToken string) error
ValidateAndStrip checks that headers contain a valid capability matching the expectedToken, then removes the CapabilityHeader from headers in place.
In production, expectedToken is the random token from BindingCapabilities. In tests, callers may use DeriveCapabilityTokenForTest to produce a deterministic token.
Returns an error if:
- CapabilityHeader is missing
- The token does not match the expectedToken
The error message MUST NOT contain the actual token value.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is an in-memory implementation of Store for unit tests.
func NewMemoryStore ¶
func NewMemoryStore(opts ...MemoryStoreOption) *MemoryStore
NewMemoryStore constructs an empty in-memory store.
func (*MemoryStore) AppendEvent ¶
AppendEvent appends an event to a task's event stream.
func (*MemoryStore) AppendMessage ¶
func (s *MemoryStore) AppendMessage(ctx context.Context, msg Message) error
AppendMessage appends a message to a task, enforcing contiguous sequence.
func (*MemoryStore) CASTask ¶
CASTask updates a task atomically using compare-and-swap on generation.
func (*MemoryStore) CreateTask ¶
func (s *MemoryStore) CreateTask(ctx context.Context, t Task) error
CreateTask persists a new task. Idempotent on caller_identity+idempotency_key.
func (*MemoryStore) GetTaskByIdempotencyKey ¶
func (s *MemoryStore) GetTaskByIdempotencyKey(ctx context.Context, callerIdentity, idempotencyKeyStr string) (*Task, error)
GetTaskByIdempotencyKey returns the task matching callerIdentity and idempotencyKey, or nil if not found.
func (*MemoryStore) ListEvents ¶
func (s *MemoryStore) ListEvents(ctx context.Context, taskID TaskID, afterSeq int64) ([]TaskEvent, error)
ListEvents returns events for a task with sequence > afterSeq.
func (*MemoryStore) ListMessages ¶
func (s *MemoryStore) ListMessages(ctx context.Context, taskID TaskID, afterSeq int64) ([]Message, error)
ListMessages returns messages for a task with sequence > afterSeq.
func (*MemoryStore) PutResult ¶
func (s *MemoryStore) PutResult(ctx context.Context, r Result) error
PutResult stores the terminal result for a task.
func (*MemoryStore) SubscribeEvents ¶
func (s *MemoryStore) SubscribeEvents(ctx context.Context, taskID TaskID, afterSeq int64) (<-chan TaskEvent, func(), error)
SubscribeEvents returns a channel of events for a task, replaying existing events with sequence > afterSeq. The channel is closed when the context is cancelled or the task's event stream reaches a terminal event.
type MemoryStoreOption ¶
type MemoryStoreOption func(*MemoryStore)
MemoryStoreOption configures a MemoryStore.
func WithMemoryClock ¶
func WithMemoryClock(now func() time.Time) MemoryStoreOption
WithMemoryClock injects a fake clock.
type Message ¶
type Message struct {
SchemaVersion string `json:"schema_version"`
MessageID MessageID `json:"message_id"`
TaskID TaskID `json:"task_id"`
WorkflowID string `json:"workflow_id"`
TenantID string `json:"tenant_id"`
// Sequence is monotonic per task, starting at 1.
Sequence int64 `json:"sequence"`
Role MessageRole `json:"role"`
SenderLogicalID string `json:"sender_logical_id"`
RecipientLogicalID string `json:"recipient_logical_id"`
Parts []MessagePart `json:"parts"`
// ContentDigest is the SHA-256 hex of the canonical parts JSON.
ContentDigest string `json:"content_digest"`
// ByteSize is the total message byte size (≤ 256 KiB).
ByteSize int64 `json:"byte_size"`
Classification Classification `json:"classification"`
CreatedAt time.Time `json:"created_at"`
// IdempotencyKey is optional.
IdempotencyKey string `json:"idempotency_key,omitempty"`
}
Message is a durable message envelope within a task. Forbidden: endpoints, IPs, DNS, ports, capability tokens, raw URLs, secret sentinels, control characters, hidden_reasoning, provider continuation identifiers.
type MessageID ¶
type MessageID string
MessageID identifies a message.
func NewMessageID ¶
NewMessageID generates a cryptographically random message ID.
type MessagePart ¶
type MessagePart struct {
Kind PartKind `json:"kind"`
// Text is bounded (max 64 KiB UTF-8). Set for kind=text, kind=error.
Text string `json:"text,omitempty"`
// JSON is a raw JSON message (size-bounded). Set for kind=json.
JSON string `json:"json,omitempty"`
// ArtifactRef is a logical artifact reference. Set for kind=artifact_ref.
ArtifactRef string `json:"artifact_ref,omitempty"`
// MediaType is the MIME type for this part.
MediaType string `json:"media_type,omitempty"`
}
MessagePart is a single typed part within a message.
type MessageRole ¶
type MessageRole string
MessageRole represents the role of a message sender.
const ( RoleUser MessageRole = "user" RoleAgent MessageRole = "agent" RoleSystem MessageRole = "system" RoleTool MessageRole = "tool" )
func AllMessageRoles ¶
func AllMessageRoles() []MessageRole
AllMessageRoles returns all valid MessageRole values.
func (MessageRole) MarshalJSON ¶
func (r MessageRole) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (*MessageRole) UnmarshalJSON ¶
func (r *MessageRole) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
func (MessageRole) Valid ¶
func (r MessageRole) Valid() bool
Valid returns true if r is a known MessageRole.
type PartKind ¶
type PartKind string
PartKind represents the kind of a message part.
func (PartKind) MarshalJSON ¶
MarshalJSON implements json.Marshaler.
func (*PartKind) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler.
type ProjectedArtifact ¶
type ProjectedArtifact struct {
ArtifactID string
Digest string
LogicalRef string
ReadOnlyRoot string
ByteSize int64
MediaType string
}
ProjectedArtifact is the read-only projection returned to a consumer. ReadOnlyRoot is a host path under the broker store — NEVER a peer container path.
type Result ¶
type Result struct {
SchemaVersion string `json:"schema_version"`
ResultID ResultID `json:"result_id"`
TaskID TaskID `json:"task_id"`
WorkflowID string `json:"workflow_id"`
// Status must match the task's terminal status.
Status TaskStatus `json:"status"`
// OutputMessageID is optional.
OutputMessageID *MessageID `json:"output_message_id,omitempty"`
// ArtifactRefs are schema-only transferable artifact references.
ArtifactRefs []TransferableArtifactRef `json:"artifact_refs,omitempty"`
// ErrorCode is a stable error code (e.g. ERR_SEQUENCE_GAP).
ErrorCode string `json:"error_code,omitempty"`
// ErrorMessage is bounded and must not contain secrets.
ErrorMessage string `json:"error_message,omitempty"`
// UsageSummary is optional (tokens/cost strings).
UsageSummary *UsageSummary `json:"usage_summary,omitempty"`
ContentDigest string `json:"content_digest"`
CreatedAt time.Time `json:"created_at"`
}
Result is the terminal result of a task.
type ResultID ¶
type ResultID string
ResultID identifies a task result.
func NewResultID ¶
NewResultID generates a cryptographically random result ID.
type SideDecision ¶
type SideDecision struct {
Evaluated bool `json:"evaluated"`
Allowed bool `json:"allowed"`
ReasonCode string `json:"reason_code,omitempty"`
ReasonDetail string `json:"reason_detail,omitempty"`
}
SideDecision records one side's authorization outcome.
type Store ¶
type Store interface {
// CreateTask persists a new task. Idempotent on caller_identity+idempotency_key.
// Returns ERR_IDEMPOTENCY_CONFLICT if the same key exists with a different body.
CreateTask(ctx context.Context, t Task) error
// GetTask returns the task by ID, or an error if not found.
GetTask(ctx context.Context, taskID TaskID) (*Task, error)
// GetTaskByIdempotencyKey returns the task by caller identity and idempotency key,
// or nil if not found.
GetTaskByIdempotencyKey(ctx context.Context, callerIdentity, idempotencyKey string) (*Task, error)
// CASTask updates a task atomically. Succeeds only if the current
// generation matches expectedGen. Returns the new generation on success.
CASTask(ctx context.Context, t Task, expectedGen int64) error
// AppendMessage appends a message to a task, enforcing contiguous
// sequence numbers (no gaps). Returns ERR_SEQUENCE_GAP if the sequence
// is not lastSeq+1.
AppendMessage(ctx context.Context, msg Message) error
// ListMessages returns messages for a task with sequence > afterSeq,
// ordered by sequence ascending.
ListMessages(ctx context.Context, taskID TaskID, afterSeq int64) ([]Message, error)
// PutResult stores the terminal result for a task. Only succeeds once
// per task and the result status must match the task's terminal status.
PutResult(ctx context.Context, r Result) error
// GetResult returns the result for a task, or an error if not found.
GetResult(ctx context.Context, taskID TaskID) (*Result, error)
// AppendEvent appends an event to a task's event stream. Returns the
// assigned sequence number.
AppendEvent(ctx context.Context, ev TaskEvent) (int64, error)
// ListEvents returns events for a task with sequence > afterSeq,
// ordered by sequence ascending.
ListEvents(ctx context.Context, taskID TaskID, afterSeq int64) ([]TaskEvent, error)
// SubscribeEvents returns a channel of events for a task, replaying
// existing events with sequence > afterSeq before delivering new events.
// The channel is closed when the context is cancelled or the task's
// event stream is closed (terminal event delivered). The returned cancel
// function unsubscribes the channel; it is safe to call more than once.
SubscribeEvents(ctx context.Context, taskID TaskID, afterSeq int64) (<-chan TaskEvent, func(), error)
}
Store is the pluggable interface for durable task delegation state. The MemoryStore implementation is suitable for unit tests.
type Task ¶
type Task struct {
SchemaVersion string `json:"schema_version"`
TaskID TaskID `json:"task_id"`
WorkflowID string `json:"workflow_id"`
TenantID string `json:"tenant_id"`
Caller CallerRef `json:"caller"`
Callee CalleeRef `json:"callee"`
// BindingID is the logical binding ID from the signed workflow.
BindingID string `json:"binding_id"`
// Capability is the logical name from the signed workflow, e.g. "report.verify".
Capability string `json:"capability"`
// Operation is optional; default "" when capability alone is enough.
Operation string `json:"operation,omitempty"`
Status TaskStatus `json:"status"`
// Generation is a monotonically increasing CAS field.
Generation int64 `json:"generation"`
// IdempotencyKey + CallerIdentity are required for admission.
IdempotencyKey string `json:"idempotency_key"`
CallerIdentity string `json:"caller_identity"`
// CommunicationSnapshotGeneration pins which workflow snapshot
// authorized this task.
CommunicationSnapshotGeneration int64 `json:"communication_snapshot_generation"`
// InputMessageID is optional until the first message is appended.
InputMessageID *MessageID `json:"input_message_id,omitempty"`
// DeadlineAt is an optional time after which the task may be expired.
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
// Budget ceilings.
MaxActiveDurationMs int64 `json:"max_active_duration_ms"`
MaxCostUsdDecimal string `json:"max_cost_usd_decimal"`
// ResultID is set when the task reaches a terminal SUCCEEDED state.
ResultID *ResultID `json:"result_id,omitempty"`
// DenialReason is set when status is DENIED.
DenialReason string `json:"denial_reason,omitempty"`
// FailureReason is set when status is FAILED.
FailureReason string `json:"failure_reason,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Task is the authoritative record for a delegated task. NO endpoints, IPs, DNS, ports, capability tokens, or container addresses in any field.
func MaybeExpireTask ¶
MaybeExpireTask checks if the task is past its deadline and non-terminal. If so, it returns the task with status set to EXPIRED and a CAS-ready copy. The caller must CAS the task to persist the expiration.
Returns (expiredTask, shouldExpire). If shouldExpire is false, the task is either already terminal or not past deadline.
type TaskEvent ¶
type TaskEvent struct {
EventID EventID `json:"event_id"`
TaskID TaskID `json:"task_id"`
WorkflowID string `json:"workflow_id"`
TenantID string `json:"tenant_id"`
Sequence int64 `json:"sequence"`
Type EventType `json:"type"`
// PayloadDigest is optional.
PayloadDigest string `json:"payload_digest,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
TaskEvent is an ordered observation event for a task. Delivery is at-least-once; consumers dedupe by task_id+sequence.
type TaskID ¶
type TaskID string
TaskID identifies a task.
type TaskOutbox ¶
type TaskOutbox struct {
// contains filtered or unexported fields
}
TaskOutbox wraps a Store so that a terminal task-CAS and its result/event commit with the same atomicity contract as trigger.Outbox. If any step fails, the caller sees the error and the mutation is treated as uncommitted.
Ordering: state CAS → PutResult → AppendEvent. If the CAS fails, result and event are never written. If the result write fails, the event is never appended. If the event append fails, the state mutation is treated as uncommitted — the caller must retry; the idempotent CAS will either succeed (fresh attempt) or conflict (already committed).
func NewTaskOutbox ¶
func NewTaskOutbox(store Store) *TaskOutbox
NewTaskOutbox creates a TaskOutbox wrapping the given Store.
func (*TaskOutbox) CommitTerminal ¶
func (o *TaskOutbox) CommitTerminal( ctx context.Context, task Task, expectedGen int64, result *Result, ev TaskEvent, ) (int64, error)
CommitTerminal atomically transitions a task to a terminal state, stores the result, and appends the terminal event.
Parameters:
- task: the current task state (used for transition validation + status)
- expectedGen: the expected generation for CAS
- result: the terminal result (must have matching Status)
- ev: the terminal TaskEvent (Type must be one of: SUCCEEDED, FAILED, CANCELLED, EXPIRED)
If the event type is TASK_DENIED, no result is stored (denied tasks don't produce results — they produce a denial reason on the task status).
Returns the sequence number of the appended event.
type TaskStatus ¶
type TaskStatus int
TaskStatus represents the lifecycle status of a delegated task.
const ( TaskStatusPending TaskStatus = iota // 0 TaskStatusAdmitted // 1 TaskStatusRunning // 2 TaskStatusSucceeded // 3 TaskStatusFailed // 4 TaskStatusCancelled // 5 TaskStatusExpired // 6 TaskStatusDenied // 7 )
func AllTaskStatuses ¶
func AllTaskStatuses() []TaskStatus
AllTaskStatuses returns all valid TaskStatus values.
func (TaskStatus) IsTerminal ¶
func (s TaskStatus) IsTerminal() bool
IsTerminal returns true for terminal task statuses.
func (TaskStatus) MarshalJSON ¶
func (s TaskStatus) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (TaskStatus) String ¶
func (s TaskStatus) String() string
String returns the string representation.
func (*TaskStatus) UnmarshalJSON ¶
func (s *TaskStatus) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
func (TaskStatus) Valid ¶
func (s TaskStatus) Valid() bool
Valid returns true if s is a known TaskStatus.
type TaskWaiter ¶
type TaskWaiter struct {
// contains filtered or unexported fields
}
TaskWaiter provides wait/subscribe APIs on top of a Store so that a parent orchestration can suspend, checkpoint, and resume without polling.
func NewTaskWaiter ¶
func NewTaskWaiter(store Store) *TaskWaiter
NewTaskWaiter creates a TaskWaiter wrapping the given Store.
func (*TaskWaiter) Subscribe ¶
func (w *TaskWaiter) Subscribe( ctx context.Context, taskID TaskID, afterSeq int64, ) (<-chan TaskEvent, func(), error)
Subscribe returns a channel of events for a task, replaying existing events with sequence > afterSeq. The returned cancel function unsubscribes the channel and closes it safely.
The channel is closed when:
- The context is cancelled.
- A terminal event is delivered.
- The cancel function is called.
func (*TaskWaiter) WaitTerminal ¶
func (w *TaskWaiter) WaitTerminal( ctx context.Context, taskID TaskID, afterSeq int64, ) (Task, []TaskEvent, error)
WaitTerminal blocks until the task reaches a terminal status, then returns the task and all events with sequence > afterSeq. The caller passes a cursor (afterSeq) to resume from a known position.
If the context is cancelled before the task becomes terminal, the method returns the context error.
type TransferableArtifactRef ¶
type TransferableArtifactRef struct {
ArtifactID string `json:"artifact_id"`
Digest string `json:"digest"` // SHA-256 hex
WorkflowID string `json:"workflow_id"`
ProducerRunID string `json:"producer_run_id"`
ProducerAttemptID string `json:"producer_attempt_id"`
ProducerTaskID string `json:"producer_task_id"`
MediaType string `json:"media_type"`
ByteSize int64 `json:"byte_size"`
Classification Classification `json:"classification"`
// Audience is the list of logical package/deployment IDs allowed to read.
Audience []string `json:"audience"`
ExpiresAt time.Time `json:"expires_at"`
// LogicalRef is a relative path (e.g. "output.json").
LogicalRef string `json:"logical_ref"`
}
TransferableArtifactRef is a reduced grant model from B32 simplification. NEVER: storage URL, raw credential, host path, shared mount path.
type TransitionError ¶
type TransitionError struct {
Resource string `json:"resource"`
FromState string `json:"from_state"`
ToState string `json:"to_state"`
Message string `json:"message"`
}
TransitionError is returned when an invalid state transition is attempted.
func (*TransitionError) Error ¶
func (e *TransitionError) Error() string
Error returns the error message.
type UsageSummary ¶
type UsageSummary struct {
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
TotalCostUsdStr string `json:"total_cost_usd_str,omitempty"`
}
UsageSummary captures optional token and cost usage.
type ValidationError ¶
ValidationError reports a schema or content validation failure.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
Error returns the error message.
type WorkflowDelegationBinding ¶
type WorkflowDelegationBinding struct {
BindingID string `json:"binding_id" yaml:"binding_id"`
Operation string `json:"operation,omitempty" yaml:"operation,omitempty"`
CalleePackageName string `json:"callee_package_name" yaml:"package_name"`
CalleePackageVersion string `json:"callee_package_version" yaml:"package_version"`
CalleeBundleDigest string `json:"callee_bundle_digest" yaml:"bundle_digest"`
CallerPackageName string `json:"caller_package_name,omitempty" yaml:"caller_package_name,omitempty"`
MaxDataClass string `json:"max_data_class" yaml:"max_data_class"`
ArtifactAudience []string `json:"artifact_audience,omitempty" yaml:"artifact_audience,omitempty"`
DeadlineMs int64 `json:"deadline_ms,omitempty" yaml:"deadline_ms,omitempty"`
MaxCostUSDDecimal string `json:"max_cost_usd_decimal,omitempty" yaml:"max_cost_usd_decimal,omitempty"`
}
WorkflowDelegationBinding represents a single delegation binding within a signed workflow snapshot. It pins the logical capability name, the exact callee package digest, optional operation, data classification ceiling, artifact audience, deadline, and budget.
type WriterKind ¶
type WriterKind string
WriterKind discriminates who is writing a message.
const ( WriterAgent WriterKind = "agent" // Agent SDK WriterRuntime WriterKind = "runtime" // Trusted runtime / gateway )
func (WriterKind) Valid ¶
func (w WriterKind) Valid() bool
Valid returns true if w is a known WriterKind.