workflow

package
v0.28.1 Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package workflow owns Avenor's durable workflow state machine.

Contract boundary

The contract boundary is owned by three cooperating layers. The JSON Schema Composition Profile v1 (schemas/workflow.profile.json) owns nested template structure (valueSchema): node, gate, output, loop, and child-workflow shapes, the action discriminator (a tagged union that rejects unknown and cross-variant fields), and additionalProperties rejection at every level. The embedded Umpire availability document owns top-level presence and required fields, plus the schema_version == 1 fairness rule. Typed Go owns the cross-node/graph/context rules and retains the checks the closed Profile vocabulary cannot express: the arbitrary-JSON leaves metadata, branches, outcome_map, and input_bindings[*].value, whose structural issues are suppressed by path so typed Go governs them; and the strict boundary guarantees of duplicate-key rejection, the 4 MiB size cap, the 64-level depth cap, and the 10,000-members-per-container cap, which the generated validator does not cover.

A template pins a schema version, template ID and version, entry nodes, declared nodes, and terminal outcomes. Nodes declare one of the action kinds run, loop, team, manual, external, or workflow. Ordinary dependency edges are acyclic. Cycles exist only through explicit bounded loops with an iteration limit, checkpoint, and exit outcomes. A workflow action pins its child template and maps only declared typed inputs, outputs, and outcomes.

Durable commands are authority checked. A command has one idempotency key; each emitted event has its own event ID and workflow-scoped sequence. The snapshot revision is the last applied workflow sequence. Execution identity combines supervisor, workflow, node, activation, and optional attempt/run/ runtime/session IDs. Completion additionally requires the active lease ID. Runtime termination, submitted completion, gate decisions, activation acceptance, and workflow completion remain distinct facts.

The MVP persists instances on a local POSIX filesystem under one configured workflow root. It uses a locked append-only event log, an atomically replaced snapshot, immutable copied evidence, and deterministic generated projections. Missing snapshots are not cataloged. The manager is hosted by the stable supervisor and is driven through explicit claim/start commands; there is no automatic scheduler or broker routing for workflow events.

Stage 4 builds the file-backed durable store: a locked append-only events.ndjson log, an atomically replaced workflow.json snapshot, POSIX flock serialization, malformed-tail-safe event replay, and a recovery catalog that replays events beyond the snapshot revision and expires only stale leases. Projection regeneration (Stage 5) is a no-op placeholder here.

Index

Constants

View Source
const (
	DefaultMaximumCompositionDepth     = 8
	DefaultMaximumCompositionChildren  = 16
	DefaultMaximumCompositionInstances = 4096
)

Default composition bounds applied when a template that composes child workflows omits composition_limits. They exist so an unbounded (or hostile) template can never explode fan-out or nest without limit; sane compositions sit far below all three. The depth bound is generous (8 levels) because nesting beyond a handful of levels is a design smell, not a need; the fan-out bound (16 children per template) keeps a single level from materializing an unbounded number of siblings. The per-template bounds do not bound the whole tree — the defaults alone permit up to ~16^8 nodes — so DefaultMaximumCompositionInstances caps the total number of instances (root plus every composed descendant) that one workflow.instantiate call may materialize, keeping the worst case a bounded few thousand store writes.

View Source
const DefaultHeartbeatInterval = 10 * time.Second

DefaultHeartbeatInterval is the advisory heartbeat cadence used when no policy declares one.

View Source
const DefaultLeaseTTL = 30 * time.Second

DefaultLeaseTTL is the lease TTL applied when neither a node's lease policy nor the template default declares one. It must be strictly positive and in the future so a claimed lease (including one reconstructed from replay) is never swept as zero-expiry on recovery.

Variables

This section is empty.

Functions

func ProjectExecutionMD

func ProjectExecutionMD(snap Snapshot, nodeID NodeID) string

ProjectExecutionMD renders a node's execution.md: that node's activations, attempts, evidence, and gate instances.

func ProjectReviewMD

func ProjectReviewMD(snap Snapshot, gi GateInstance) string

ProjectReviewMD renders a gate instance's review-N.md: the gate summary plus the evidence it references.

func ProjectWorkflowMD

func ProjectWorkflowMD(snap Snapshot) string

ProjectWorkflowMD renders the instance-level workflow.md.

func SetCompletionGateResolver

func SetCompletionGateResolver(fn func(templateID TemplateID, templateVersion TemplateVersion, nodeID NodeID) []GateDefinition)

SetCompletionGateResolver wires the template-aware gate lookup used by the completion path: when a completion leaves required gates unsatisfied, the activation is parked awaiting_gate instead of being satisfied. It is owned by the manager (which can resolve the instance's versioned template); the reducer defaults to no-gate behavior when unset.

func SetRetryPolicyResolver

func SetRetryPolicyResolver(fn func(templateID TemplateID, templateVersion TemplateVersion, nodeID NodeID) *RetryPolicy)

SetRetryPolicyResolver wires the template-aware retry policy lookup used by attempt_terminated handling. It is owned by the store (which can resolve the instance's versioned template); the reducer defaults to single-attempt behavior when unset.

func ValidateGraph

func ValidateGraph(template Template) error

ValidateGraph enforces the typed, cross-node graph rules that the closed Profile vocabulary cannot express. It is pure: it reads only template and never touches I/O. It assumes the structural (field-presence, action-variant, non-blank-id) checks have already run or will run; this function owns graph shape: node reference integrity, duplicate containment, the ordinary acyclic dependency graph, bounded loop well-formedness, composition-limit bounds, and workflow-action input-binding reference legality.

The Branches map of a node is itself the declaration of its branch outcomes: branch keys do not need to be listed in the node's Outcomes, and TerminalOutcomes is a template-global vocabulary whose entries need not be redeclared as Terminal on any node.

ValidateGraph deliberately terminates at the first violation so the message pinpoints the earliest structural break, mirroring the sibling ValidateTemplate walk's fail-fast contract.

func ValidateTemplate

func ValidateTemplate(template Template) error

ValidateTemplate evaluates the generated portable Umpire contract and the typed structural checks. Stage 3 adds graph- and context-dependent rules.

func ValidateTemplateJSON

func ValidateTemplateJSON(data []byte) error

ValidateTemplateJSON strictly decodes and validates a workflow template.

func WorkflowProfileStructuralIntParts

func WorkflowProfileStructuralIntParts(raw json.RawMessage) (val int64, isInt, safe bool)

WorkflowProfileStructuralIntParts splits a JSON number literal into an integer value, whether it was an integer literal, and whether it lies within JavaScript's safe-integer range (|v| <= 2^53-1).

func WorkflowProfileStructuralKind

func WorkflowProfileStructuralKind(raw json.RawMessage) string

WorkflowProfileStructuralKind reports the JSON value kind of a raw token.

func WriteProjections

func WriteProjections(dir string, snap Snapshot) error

WriteProjections renders every projection for snap and writes the files under dir (the instance directory). It creates node directories as needed. A projection is a derived artifact: callers (the store) treat an error as non-fatal, so this never blocks a committed state transition.

Types

type Action

type Action struct {
	Kind     ActionKind      `json:"-"`
	Run      *RunAction      `json:"-"`
	Loop     *LoopAction     `json:"-"`
	Team     *TeamAction     `json:"-"`
	Manual   *ManualAction   `json:"-"`
	External *ExternalAction `json:"-"`
	Workflow *WorkflowAction `json:"-"`
}

Action is a strict tagged union. Exactly one variant pointer corresponds to Kind; MarshalJSON and UnmarshalJSON use the flat {"type": ...} wire shape.

func (Action) MarshalJSON

func (action Action) MarshalJSON() ([]byte, error)

func (*Action) UnmarshalJSON

func (action *Action) UnmarshalJSON(data []byte) error

type ActionKind

type ActionKind string

ActionKind selects the executor attached to a node.

const (
	ActionRun      ActionKind = "run"
	ActionLoop     ActionKind = "loop"
	ActionTeam     ActionKind = "team"
	ActionManual   ActionKind = "manual"
	ActionExternal ActionKind = "external"
	ActionWorkflow ActionKind = "workflow"
)

type Activation

type Activation struct {
	ID              ActivationID        `json:"activation_id"`
	NodeID          NodeID              `json:"node_id"`
	Iteration       int                 `json:"iteration"`
	IncomingOutcome OutcomeName         `json:"incoming_outcome,omitempty"`
	Status          ActivationStatus    `json:"status"`
	Selection       *ExecutionSelection `json:"selection,omitempty"`
	AttemptIDs      []AttemptID         `json:"attempt_ids,omitempty"`
	ActiveLease     *Lease              `json:"active_lease,omitempty"`
	SelectedOutcome OutcomeName         `json:"selected_outcome,omitempty"`
	CreatedAt       time.Time           `json:"created_at"`
	UpdatedAt       time.Time           `json:"updated_at"`
}

type ActivationID

type ActivationID string

func NewActivationID

func NewActivationID() ActivationID

type ActivationStatus

type ActivationStatus string

ActivationStatus is the lifecycle state of one visit to a node.

const (
	ActivationPending            ActivationStatus = "pending"
	ActivationReady              ActivationStatus = "ready"
	ActivationLeased             ActivationStatus = "leased"
	ActivationRunning            ActivationStatus = "running"
	ActivationSkipped            ActivationStatus = "skipped"
	ActivationAttemptFailed      ActivationStatus = "attempt_failed"
	ActivationAwaitingCompletion ActivationStatus = "awaiting_completion"
	ActivationAwaitingGate       ActivationStatus = "awaiting_gate"
	ActivationAwaitingChild      ActivationStatus = "awaiting_child"
	ActivationBlocked            ActivationStatus = "blocked"
	ActivationLeaseExpired       ActivationStatus = "lease_expired"
	ActivationSatisfied          ActivationStatus = "satisfied"
	ActivationRejected           ActivationStatus = "rejected"
)

type ArtifactRequirement

type ArtifactRequirement struct {
	Path     string `json:"path"`
	NonEmpty bool   `json:"non_empty,omitempty"`
	SHA256   string `json:"sha256,omitempty"`
}

type Assignment

type Assignment struct {
	Role        string `json:"role,omitempty"`
	RosterFile  string `json:"roster_file,omitempty"`
	RosterEntry string `json:"roster_entry,omitempty"`
	Backend     string `json:"backend,omitempty"`
	Agent       string `json:"agent,omitempty"`
	Model       string `json:"model,omitempty"`
	Thinking    string `json:"thinking,omitempty"`
}

type Attempt

type Attempt struct {
	ID               AttemptID         `json:"attempt_id"`
	Identity         ExecutionIdentity `json:"identity"`
	Status           AttemptStatus     `json:"status"`
	Backend          string            `json:"backend,omitempty"`
	Agent            string            `json:"agent,omitempty"`
	Model            string            `json:"model,omitempty"`
	WorkingDirectory string            `json:"working_directory,omitempty"`
	Worktree         string            `json:"worktree,omitempty"`
	BaseGitSHA       string            `json:"base_git_sha,omitempty"`
	EndingGitSHA     string            `json:"ending_git_sha,omitempty"`
	EventPath        string            `json:"event_path,omitempty"`
	SentinelPath     string            `json:"sentinel_path,omitempty"`
	ArtifactPaths    []string          `json:"artifact_paths,omitempty"`
	StartedAt        time.Time         `json:"started_at"`
	EndedAt          *time.Time        `json:"ended_at,omitempty"`
	MarkerKind       string            `json:"marker_kind,omitempty"`
	MarkerLabel      string            `json:"marker_label,omitempty"`
	FailureClass     string            `json:"failure_class,omitempty"`
	Corrections      int               `json:"corrections,omitempty"`
}

type AttemptID

type AttemptID string

func NewAttemptID

func NewAttemptID() AttemptID

type AttemptStatus

type AttemptStatus string

AttemptStatus records execution separately from activation acceptance.

const (
	AttemptStarting  AttemptStatus = "starting"
	AttemptRunning   AttemptStatus = "running"
	AttemptSucceeded AttemptStatus = "succeeded"
	AttemptFailed    AttemptStatus = "failed"
	AttemptCanceled  AttemptStatus = "canceled"
	AttemptTimedOut  AttemptStatus = "timed_out"
	AttemptPanicked  AttemptStatus = "panicked"
)

type AuthorityRule

type AuthorityRule struct {
	Authorities    []string `json:"authorities"`
	ReasonRequired bool     `json:"reason_required,omitempty"`
}

type BoundedLoopDefinition

type BoundedLoopDefinition struct {
	ID           LoopID        `json:"id"`
	BodyNodes    []NodeID      `json:"body_nodes"`
	EntryNodeID  NodeID        `json:"entry_node_id"`
	CheckpointID NodeID        `json:"checkpoint_node_id"`
	MaximumRuns  int           `json:"maximum_iterations"`
	ExitOutcomes []OutcomeName `json:"exit_outcomes"`
}

type CatalogedInstance

type CatalogedInstance struct {
	WorkflowID WorkflowID
	Snapshot   Snapshot
}

CatalogedInstance pairs a workflow ID with its recovered snapshot.

type ChallengeResult

type ChallengeResult struct {
	FieldName    string
	Status       FieldStatus
	Explanations []string
}

ChallengeResult holds the result of a Challenge call.

type CheckpointDefinition

type CheckpointDefinition struct {
	Path            string        `json:"path"`
	ExitOutcomes    []OutcomeName `json:"exit_outcomes"`
	RequiresRelease bool          `json:"requires_release,omitempty"`
}

type ChildReference

type ChildReference struct {
	ID               ChildReferenceID  `json:"child_reference_id"`
	NodeID           NodeID            `json:"node_id,omitempty"`
	ParentActivation ActivationID      `json:"parent_activation_id"`
	WorkflowID       WorkflowID        `json:"workflow_id"`
	TemplateID       TemplateID        `json:"template_id"`
	TemplateVersion  TemplateVersion   `json:"template_version"`
	Outputs          []OutputReference `json:"outputs,omitempty"`
	Outcome          OutcomeName       `json:"outcome,omitempty"`
}

type ChildReferenceID

type ChildReferenceID string

func NewChildReferenceID

func NewChildReferenceID() ChildReferenceID

type Command

type Command struct {
	ID               CommandID         `json:"command_id"`
	Kind             CommandKind       `json:"kind"`
	Identity         ExecutionIdentity `json:"identity"`
	ExpectedRevision int64             `json:"expected_revision"`
	IdempotencyKey   string            `json:"idempotency_key"`
	LeaseID          LeaseID           `json:"lease_id,omitempty"`
	Actor            string            `json:"actor,omitempty"`
	Reason           string            `json:"reason,omitempty"`
	Outcome          OutcomeName       `json:"outcome,omitempty"`
	AttemptStatus    AttemptStatus     `json:"attempt_status,omitempty"`
	MarkerKind       string            `json:"marker_kind,omitempty"`
	MarkerLabel      string            `json:"marker_label,omitempty"`
	Evidence         []Evidence        `json:"evidence,omitempty"`
	Outputs          []OutputValue     `json:"outputs,omitempty"`
	Gate             *GateInstance     `json:"gate,omitempty"`
	// Operation selects the gate decision; only meaningful for CommandGate,
	// ignored for every other command kind.
	Operation GateOperation       `json:"operation,omitempty"`
	Lease     *Lease              `json:"lease,omitempty"`
	Selection *ExecutionSelection `json:"selection,omitempty"`
	// ChildOutputs is the CommandChildOutcome selection of child output
	// references (identity only, no child state copied into the parent).
	ChildOutputs []OutputReference `json:"child_outputs,omitempty"`
	Payload      json.RawMessage   `json:"payload,omitempty"`
}

Command is the pure reducer input. Stage-specific handlers validate and fill only the fields relevant to Kind.

type CommandID

type CommandID string

func NewCommandID

func NewCommandID() CommandID

type CommandKind

type CommandKind string

CommandKind names reducer commands without importing control-plane types.

const (
	CommandInstantiate  CommandKind = "instantiate"
	CommandClaim        CommandKind = "claim"
	CommandStart        CommandKind = "start"
	CommandComplete     CommandKind = "complete"
	CommandGate         CommandKind = "gate"
	CommandSkip         CommandKind = "skip"
	CommandUnblock      CommandKind = "unblock"
	CommandReroute      CommandKind = "reroute"
	CommandHeartbeat    CommandKind = "heartbeat"
	CommandTerminate    CommandKind = "terminate_attempt"
	CommandChildAttach  CommandKind = "child_attach"
	CommandChildOutcome CommandKind = "child_outcome"
)

type CompletionContract

type CompletionContract struct {
	Kind      CompletionContractKind `json:"kind"`
	Artifacts []ArtifactRequirement  `json:"artifacts,omitempty"`
	Git       *GitRequirement        `json:"git,omitempty"`
}

type CompletionContractKind

type CompletionContractKind string

CompletionContractKind selects a safe machine completion evaluator.

const (
	CompletionExplicit CompletionContractKind = "explicit"
	CompletionFiles    CompletionContractKind = "files"
	CompletionGit      CompletionContractKind = "git"
)

type Composition

type Composition struct {
	Children []CompositionChild
}

Composition is the validated composition manifest for one template: one entry per workflow-action node, in node order. It is the pure, store-free output of BuildComposition; the manager converts entries into durable ChildReference records and materializes the child instances.

func BuildComposition

func BuildComposition(parent WorkflowID, root Template, resolve TemplateResolver) (Composition, int, error)

BuildComposition validates the compose prerequisites of root (pinned versions resolve, no composition cycles, depth and fan-out within the effective limits, total instance count within the global cap, and all output/outcome bindings declared) and returns the composition manifest — one entry per workflow-action node of root, in node order — plus the total number of instances the tree would materialize (root plus every composed descendant). It is pure: the only I/O it performs is through resolve, and parent is only used to derive the deterministic child workflow IDs. A template with no workflow-action nodes composes nothing and yields an empty manifest without consulting the resolver.

type CompositionChild

type CompositionChild struct {
	NodeID          NodeID
	ChildWorkflowID WorkflowID
	Template        Template
}

CompositionChild identifies one workflow-action node and the child instance it composes. Template is the resolved pinned child template (used by the manager to instantiate the child recursively); it is not part of the durable record.

type CompositionLimits

type CompositionLimits struct {
	MaximumDepth    int `json:"max_depth"`
	MaximumChildren int `json:"max_children"`
}

type Event

type Event struct {
	ID             EventID           `json:"id"`
	Kind           EventKind         `json:"kind"`
	Sequence       int64             `json:"sequence"`
	CommandID      CommandID         `json:"command_id,omitempty"`
	IdempotencyKey string            `json:"idempotency_key,omitempty"`
	Identity       ExecutionIdentity `json:"identity"`
	AttemptID      AttemptID         `json:"attempt_id,omitempty"`
	LeaseID        LeaseID           `json:"lease_id,omitempty"`
	Actor          string            `json:"actor,omitempty"`
	Reason         string            `json:"reason,omitempty"`
	Outcome        OutcomeName       `json:"outcome,omitempty"`
	AttemptStatus  AttemptStatus     `json:"attempt_status,omitempty"`
	MarkerKind     string            `json:"marker_kind,omitempty"`
	MarkerLabel    string            `json:"marker_label,omitempty"`
	Gate           *GateInstance     `json:"gate,omitempty"`
	Transition     *Transition       `json:"transition,omitempty"`
	Evidence       []Evidence        `json:"evidence,omitempty"`
	Outputs        []OutputValue     `json:"outputs,omitempty"`
	// ChildOutputs is the EventChildOutcome payload's selection of child
	// output references (identity only, no child state) recorded on the
	// parent's durable child reference.
	ChildOutputs []OutputReference   `json:"child_outputs,omitempty"`
	Iteration    int                 `json:"iteration,omitempty"`
	Selection    *ExecutionSelection `json:"selection,omitempty"`
	Instantiated *InstanceRecord     `json:"instantiated,omitempty"`
	LeaseTargets []NodeID            `json:"lease_targets,omitempty"`
	Lease        *Lease              `json:"lease,omitempty"`
}

Event is one record in the workflow store's NDJSON log. It carries its own event ID and workflow-scoped sequence (assigned by the manager/store in Stage 4). The batch produced for one command shares the command's idempotency key. Fields are optional per Kind.

func Apply

func Apply(state Snapshot, command Command) ([]Event, error)

Apply turns a validated command into the batch of events that records its effect. It is a pure projection of (Snapshot, Command) -> []Event: nothing is mutated and nothing is persisted here. The returned events must be reduced (via Reduce) in order to advance the instance.

Apply is the only place that consults the caller-supplied expectations (expected revision, idempotency). Event-level state transitions live in transitions.go (applyEvent), which stays purely replay-driven.

type EventID

type EventID string

func NewEventID

func NewEventID() EventID

type EventKind

type EventKind string

EventKind names a workflow-store event. Workflow events are workflow-local and distinct from runtime session events (internal/events).

const (
	EventInstantiated      EventKind = "workflow.event.instantiated"
	EventLeased            EventKind = "workflow.event.leased"
	EventStarted           EventKind = "workflow.event.started"
	EventAttemptTerminated EventKind = "workflow.event.attempt_terminated"
	EventCompleted         EventKind = "workflow.event.completed"
	EventGate              EventKind = "workflow.event.gate"
	EventSkipped           EventKind = "workflow.event.skipped"
	EventUnblocked         EventKind = "workflow.event.unblocked"
	EventRerouted          EventKind = "workflow.event.rerouted"
	EventHeartbeat         EventKind = "workflow.event.heartbeat"
	EventLeaseExpired      EventKind = "workflow.event.lease_expired"
	EventTransition        EventKind = "workflow.event.transition"
	EventChildAttached     EventKind = "workflow.event.child_attached"
	EventChildOutcome      EventKind = "workflow.event.child_outcome"
)

type Evidence

type Evidence struct {
	ID           EvidenceID      `json:"evidence_id"`
	Kind         string          `json:"kind"`
	Source       EvidenceSource  `json:"source"`
	Authority    string          `json:"authority"`
	OriginalPath string          `json:"original_path,omitempty"`
	StoredPath   string          `json:"stored_path,omitempty"`
	Size         int64           `json:"size,omitempty"`
	SHA256       string          `json:"sha256,omitempty"`
	Result       json.RawMessage `json:"result,omitempty"`
	CreatedAt    time.Time       `json:"created_at"`
	ActivationID ActivationID    `json:"activation_id"`
	Subject      *Subject        `json:"subject,omitempty"`
}

type EvidenceID

type EvidenceID string

func NewEvidenceID

func NewEvidenceID() EvidenceID

type EvidenceSource

type EvidenceSource string

EvidenceSource identifies the authority that supplied evidence.

const (
	EvidenceMachine  EvidenceSource = "machine"
	EvidenceAgent    EvidenceSource = "agent"
	EvidenceHuman    EvidenceSource = "human"
	EvidenceExternal EvidenceSource = "external"
)

type ExecutionIdentity

type ExecutionIdentity struct {
	SupervisorID string       `json:"supervisor_id"`
	WorkflowID   WorkflowID   `json:"workflow_id"`
	NodeID       NodeID       `json:"node_id"`
	ActivationID ActivationID `json:"activation_id"`
	AttemptID    AttemptID    `json:"attempt_id,omitempty"`
	RunID        string       `json:"run_id,omitempty"`
	RuntimeID    string       `json:"runtime_id,omitempty"`
	SessionID    string       `json:"session_id,omitempty"`
}

type ExecutionSelection

type ExecutionSelection struct {
	Role         string `json:"role,omitempty"`
	Backend      string `json:"backend,omitempty"`
	Agent        string `json:"agent,omitempty"`
	Model        string `json:"model,omitempty"`
	Thinking     string `json:"thinking,omitempty"`
	RosterDigest string `json:"roster_digest,omitempty"`
}

type Executor

type Executor interface {
	Dispatch(ctx context.Context, ec ExecutorContext) error
}

Executor dispatches a started action to its runtime backend. The manager records the attempt durably before calling Dispatch, so an executor that crashes leaves the attempt in the log for recovery. Stage 6 registers no real providers; tests use a fake.

type ExecutorContext

type ExecutorContext struct {
	WorkflowID   WorkflowID
	NodeID       NodeID
	ActivationID ActivationID
	AttemptID    AttemptID
	LeaseID      LeaseID
	// OwnerToken is the raw claim owner token for this attempt's lease. It is
	// additive and inert: the reducer/store never sees it, but the executor
	// layer can use it (with LeaseID) to renew its own lease via
	// Manager.Heartbeat — the owner-token heartbeat seam. A live heartbeat
	// goroutine in the executors is a later hardening, not part of this stage.
	// Executors must never marshal ExecutorContext (or OwnerToken) into the workflow store's snapshots or event log, so the raw claim token can never become durable.
	OwnerToken string
	Action     Action
	Selection  *ExecutionSelection
}

ExecutorContext carries everything a backend needs to run one attempt.

type ExternalAction

type ExternalAction struct {
	Source      string `json:"source"`
	SubjectType string `json:"subject_type,omitempty"`
}

type FieldStatus

type FieldStatus struct {
	Enabled   bool     `json:"enabled"`
	Required  bool     `json:"required"`
	Satisfied bool     `json:"satisfied"`
	Fair      bool     `json:"fair"`
	Reason    *string  `json:"reason"`
	Reasons   []string `json:"reasons"`
	Valid     *bool    `json:"valid,omitempty"`
	Error     string   `json:"error,omitempty"`
}

FieldStatus mirrors the conformance expectedAvailability shape exactly. Valid and Error are omitted unless a named validator runs for an enabled, satisfied field.

type GateDefinition

type GateDefinition struct {
	ID              GateID        `json:"id"`
	Name            string        `json:"name,omitempty"`
	Type            GateType      `json:"type"`
	Required        bool          `json:"required"`
	AllowedOutcomes []OutcomeName `json:"allowed_outcomes,omitempty"`
	SubjectType     string        `json:"subject_type,omitempty"`
}

type GateID

type GateID string

type GateInstance

type GateInstance struct {
	ID           GateInstanceID `json:"gate_instance_id"`
	GateID       GateID         `json:"gate_id"`
	ActivationID ActivationID   `json:"activation_id"`
	Status       GateStatus     `json:"status"`
	Outcome      OutcomeName    `json:"outcome,omitempty"`
	Actor        string         `json:"actor,omitempty"`
	Reason       string         `json:"reason,omitempty"`
	Subject      *Subject       `json:"subject,omitempty"`
	PollID       string         `json:"poll_id,omitempty"`
	Source       string         `json:"source,omitempty"`
	ResponseHash string         `json:"response_hash,omitempty"`
	EvidenceIDs  []EvidenceID   `json:"evidence_ids,omitempty"`
	ObservedAt   *time.Time     `json:"observed_at,omitempty"`
	DecidedAt    *time.Time     `json:"decided_at,omitempty"`
}

type GateInstanceID

type GateInstanceID string

func NewGateInstanceID

func NewGateInstanceID() GateInstanceID

type GateOperation

type GateOperation string

GateOperation selects the decision recorded by a CommandGate. It is a closed set: the manager validates against it, and the reducer re-validates.

const (
	GateOpSatisfy        GateOperation = "satisfy"
	GateOpReject         GateOperation = "reject"
	GateOpWaive          GateOperation = "waive"
	GateOpExternalResult GateOperation = "external_result"
)

type GateStatus

type GateStatus string

GateStatus is the durable result of one gate instance.

const (
	GatePending          GateStatus = "pending"
	GatePassed           GateStatus = "passed"
	GateFailed           GateStatus = "failed"
	GateActionRequired   GateStatus = "action_required"
	GateChangesRequested GateStatus = "changes_requested"
	GateRejected         GateStatus = "rejected"
	GateWaived           GateStatus = "waived"
)

type GateType

type GateType string

GateType identifies who or what has authority to decide a gate.

const (
	GateMachine  GateType = "machine"
	GateExternal GateType = "external"
	GateHuman    GateType = "human"
)

type GitRequirement

type GitRequirement struct {
	Clean           bool   `json:"clean,omitempty"`
	Head            string `json:"head,omitempty"`
	ChangedFromBase bool   `json:"changed_from_base,omitempty"`
}

type InputBinding

type InputBinding struct {
	Input string                   `json:"input"`
	Value json.RawMessage          `json:"value,omitempty"`
	From  *TemplateOutputReference `json:"from,omitempty"`
}

type InstanceID

type InstanceID string

func NewInstanceID

func NewInstanceID() InstanceID

type InstanceRecord

type InstanceRecord struct {
	TemplateID       TemplateID       `json:"template_id"`
	TemplateVersion  TemplateVersion  `json:"template_version"`
	TerminalOutcomes []OutcomeName    `json:"terminal_outcomes"`
	EntryNodes       []NodeID         `json:"entry_nodes"`
	Children         []ChildReference `json:"children,omitempty"`
}

InstanceRecord is the payload of EventInstantiated: enough immutable context to reconstruct the initial instance from the template entry contract.

type Issue

type Issue struct {
	Code string `json:"code"`
	Path string `json:"path"`
}

Issue describes one validation problem with an RFC 6901 JSON Pointer path.

type Lease

type Lease struct {
	ID              LeaseID      `json:"lease_id"`
	ActivationID    ActivationID `json:"activation_id"`
	Owner           string       `json:"owner"`
	TokenDigest     string       `json:"token_digest"`
	AcquiredAt      time.Time    `json:"acquired_at"`
	ExpiresAt       time.Time    `json:"expires_at"`
	LastHeartbeatAt *time.Time   `json:"last_heartbeat_at,omitempty"`
	LastActivityAt  *time.Time   `json:"last_activity_at,omitempty"`
}

type LeaseExpirySummary

type LeaseExpirySummary struct {
	// Expired is the number of stale leases this sweep's own "stale" pass
	// expired to ActivationLeaseExpired. (Leases already expired by an earlier
	// recovery pass carry no ActiveLease and are not counted here.)
	Expired int
	// Retained is the number of leases left in place: every non-stale active
	// lease plus the exempted awaiting_child claims (whose kernel-held lease
	// survives regardless of staleness).
	Retained int
	// Errors is one entry per instance whose sweep failed. Errored instances
	// are left as-is and retried on the next sweep.
	Errors []string
}

LeaseExpirySummary reports the outcome of one live lease-expiry sweep.

type LeaseID

type LeaseID string

func NewLeaseID

func NewLeaseID() LeaseID

type LeasePolicy

type LeasePolicy struct {
	TTLSeconds               int64 `json:"ttl_seconds"`
	HeartbeatIntervalSeconds int64 `json:"heartbeat_interval_seconds,omitempty"`
}

type LoopAction

type LoopAction struct {
	LoopFile string `json:"loop_file"`
}

type LoopID

type LoopID string

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

func NewManager

func NewManager(store *Store) *Manager

func (*Manager) ExpireStaleLeases

func (m *Manager) ExpireStaleLeases() (LeaseExpirySummary, error)

ExpireStaleLeases is the manager's live stall detector: it scans every instance and expires leases whose liveness is stale (now strictly after the lease's ExpiresAt). It performs its own sweep with reason "stale", distinct from restart recovery (reason "recovery"), so it is runnable live by the manager rather than only on restart — a node whose holder stopped heartbeating is reclaimed without a supervisor restart. It enumerates the instance directory itself and never invokes the recovery path (Catalog), whose recovery sweep would otherwise expire the same leases first with the wrong reason. Activity never renews ExpiresAt (only an explicit heartbeat does), so the single staleness oracle now.After(ExpiresAt) correctly implements "activity alone does not extend liveness". It is idempotent: an already-expired lease carries no ActiveLease and is never swept twice.

func (*Manager) Heartbeat

func (m *Manager) Heartbeat(wf WorkflowID, nodeID NodeID, activationID ActivationID, leaseID LeaseID, ownerToken string) error

Heartbeat is the executor-facing convenience wrapper around the "heartbeat" command (see commandHeartbeat): it renews the activation's active lease for a caller identified by the claim's (leaseID, ownerToken) pair — the same pair a claim returns and that the start carries into ExecutorContext.OwnerToken. It never transitions the activation status.

func (*Manager) RecordAttemptTerminated

func (m *Manager) RecordAttemptTerminated(wf WorkflowID, nodeID NodeID, activationID ActivationID, attemptID AttemptID, leaseID LeaseID, status AttemptStatus, marker ...string) error

RecordAttemptTerminated records the terminal status of an already-started attempt after its backend run finishes. It is called by a runtime executor (the stable supervisor's direct-run executor) on every terminal path: success, failure, panic, cancellation, timeout, and provider-start error. It is idempotent per attempt so duplicate terminations are safe.

The optional trailing marker args carry inert terminal-marker evidence (marker kind first, marker label second). Markers are recorded on the attempt as evidence only; they are never a workflow-store command and cannot satisfy an activation or select an outcome.

func (*Manager) RegisterExecutor

func (m *Manager) RegisterExecutor(kind ActionKind, exec Executor)

RegisterExecutor attaches the dispatch backend for one action kind.

func (*Manager) ResumeAwaitingChildren

func (m *Manager) ResumeAwaitingChildren() (ResumeAwaitingChildrenSummary, error)

ResumeAwaitingChildren is the manager's restart hook: after a supervisor restart it resumes every awaiting_child activation in the store by identity. For each such activation it reads the durable composition-manifest child reference for the node and loads the child workflow; when the child is already terminal it replays the same outcome-mapping resolution the live executor uses (resolveChildOutcome), reconstructing the ExecutorContext from durable state only — the activation's active claim lease and its existing attempt ID (so the child-attach/child-outcome idempotency keys stay stable across the restart). A parent whose child is not yet terminal is left in awaiting_child: this is not a scheduler, and it never re-creates a child, re-attaches, or re-awaits. It is idempotent — an already-resolved parent is no longer awaiting_child and is skipped, and the child-outcome command is idempotent per attempt — so a duplicate resume is a safe no-op.

func (*Manager) WorkflowCommand

func (m *Manager) WorkflowCommand(id string, payload json.RawMessage) (any, error)

WorkflowCommand routes an instance command by its "op" discriminator.

func (*Manager) WorkflowCreate

func (m *Manager) WorkflowCreate(payload json.RawMessage) (any, error)

WorkflowCreate validates and stores a versioned template.

func (*Manager) WorkflowEvents

func (m *Manager) WorkflowEvents(id string, afterSeq int64, limit int) (any, error)

WorkflowEvents returns log events with Sequence > afterSeq, capped at limit (limit <= 0 caps at 1000).

func (*Manager) WorkflowInspect

func (m *Manager) WorkflowInspect(id string) (any, error)

WorkflowInspect returns the full instance detail.

func (*Manager) WorkflowInstantiate

func (m *Manager) WorkflowInstantiate(payload json.RawMessage) (any, error)

WorkflowInstantiate instantiates a stored template as a new active workflow. When the template composes child workflows, the compose prerequisites are validated up front (pinned versions resolve across the whole descendant tree, no cycles, all bounds respected) and the child instances are materialized eagerly — idempotently, under deterministic derived IDs — before the parent's instantiate command is applied, so the parent's event log never references children that do not exist. The eager materialization is intentional: every composed child is created as an active instance (its entry activation pending) ahead of the parent's own commit, and child execution stays gated on the parent's workflow-node attach in a later phase — nothing auto-claims a child. Child creation is idempotent through the derived IDs: a replay that finds the child already present resumes it as-is, while a concurrent creator surfaces as a revision mismatch rather than being silently absorbed. If materialization fails partway, the already-created children are left on disk as active, unparented workflows and the caller receives only the error; orphan cleanup is out of scope for this stage. The composition manifest rides on the instantiate event record and is applied into the instance by the reducer.

func (*Manager) WorkflowStatus

func (m *Manager) WorkflowStatus(id string) (any, error)

WorkflowStatus returns a compact status view of a workflow instance.

func (*Manager) WorkflowWait

func (m *Manager) WorkflowWait(id string, timeout time.Duration) (any, error)

WorkflowWait polls the instance until its status is terminal or the timeout elapses. A timeout <= 0 returns after the first poll.

type ManualAction

type ManualAction struct {
	Instructions string `json:"instructions,omitempty"`
}

type NodeDefinition

type NodeDefinition struct {
	ID           NodeID                 `json:"id"`
	Name         string                 `json:"name,omitempty"`
	Dependencies []NodeID               `json:"dependencies,omitempty"`
	Outcomes     []OutcomeDefinition    `json:"outcomes,omitempty"`
	Branches     map[OutcomeName]NodeID `json:"branches,omitempty"`
	Action       Action                 `json:"action"`
	Assignment   *Assignment            `json:"assignment,omitempty"`
	Completion   *CompletionContract    `json:"completion,omitempty"`
	Outputs      []OutputDefinition     `json:"outputs,omitempty"`
	Gates        []GateDefinition       `json:"gates,omitempty"`
	RetryPolicy  *RetryPolicy           `json:"retry_policy,omitempty"`
	LoopID       LoopID                 `json:"loop_id,omitempty"`
	Checkpoint   *CheckpointDefinition  `json:"checkpoint,omitempty"`
	LeasePolicy  *LeasePolicy           `json:"lease_policy,omitempty"`
	SkipRule     *AuthorityRule         `json:"skip_rule,omitempty"`
	WaiveRules   []AuthorityRule        `json:"waive_rules,omitempty"`
}

type NodeID

type NodeID string

type OutcomeDefinition

type OutcomeDefinition struct {
	Name         OutcomeName `json:"name"`
	TargetNodeID NodeID      `json:"target_node_id,omitempty"`
	Terminal     bool        `json:"terminal,omitempty"`
}

type OutcomeName

type OutcomeName string

type OutputBinding

type OutputBinding struct {
	ChildOutput  string `json:"child_output"`
	ParentOutput string `json:"parent_output"`
}

type OutputDefinition

type OutputDefinition struct {
	ID       OutputID   `json:"id"`
	Name     string     `json:"name"`
	Type     OutputType `json:"type"`
	Required bool       `json:"required,omitempty"`
}

type OutputID

type OutputID string

func NewOutputID

func NewOutputID() OutputID

type OutputReference

type OutputReference struct {
	WorkflowID   WorkflowID   `json:"workflow_id"`
	NodeID       NodeID       `json:"node_id"`
	ActivationID ActivationID `json:"activation_id"`
	OutputID     OutputID     `json:"output_id"`
	Revision     int64        `json:"revision"`
}

type OutputType

type OutputType string

OutputType is the portable type of a declared workflow output.

const (
	OutputString  OutputType = "string"
	OutputNumber  OutputType = "number"
	OutputBoolean OutputType = "boolean"
	OutputJSON    OutputType = "json"
	OutputFile    OutputType = "file"
)

type OutputValue

type OutputValue struct {
	ID           OutputID        `json:"id"`
	DefinitionID OutputID        `json:"definition_id"`
	ActivationID ActivationID    `json:"activation_id"`
	Revision     int64           `json:"revision"`
	Value        json.RawMessage `json:"value"`
	EvidenceIDs  []EvidenceID    `json:"evidence_ids,omitempty"`
	CreatedAt    time.Time       `json:"created_at"`
}

type ResumeAwaitingChildrenSummary

type ResumeAwaitingChildrenSummary struct {
	// Resolved is the number of awaiting_child parents whose child is already
	// terminal and whose mapped outcome was replayed on this call.
	Resolved int
	// StillAwaiting is the number of awaiting_child parents that remain
	// awaiting_child afterwards: the child is not yet terminal (or is missing
	// or unmappable), so a real driver must re-dispatch the wait later.
	StillAwaiting int
	// Errors is one entry per parent whose replay failed (child instance
	// unreadable, unmapped terminal outcome, ...). Error parents remain
	// awaiting_child and are retried on the next resume.
	Errors []string
}

ResumeAwaitingChildrenSummary reports the outcome of one resume sweep.

type RetryExhaustionKind

type RetryExhaustionKind string

RetryExhaustionKind controls what happens after the activation retry budget.

const (
	RetryExhaustionBlock   RetryExhaustionKind = "block"
	RetryExhaustionFail    RetryExhaustionKind = "fail"
	RetryExhaustionOutcome RetryExhaustionKind = "outcome"
)

type RetryPolicy

type RetryPolicy struct {
	MaximumAttempts int                 `json:"max_attempts"`
	Exhaustion      RetryExhaustionKind `json:"exhaustion"`
	Outcome         OutcomeName         `json:"outcome,omitempty"`
}

type RuleMetaEntry

type RuleMetaEntry struct {
	Field    string
	RuleType string
	Expr     string
	Reason   string
}

RuleMetaEntry holds metadata about a rule for Challenge output.

type RunAction

type RunAction struct {
	Prompt     string `json:"prompt,omitempty"`
	PromptFile string `json:"prompt_file,omitempty"`
}

type Snapshot

type Snapshot struct {
	SchemaVersion   int                  `json:"schema_version"`
	Instance        WorkflowInstance     `json:"instance"`
	AppliedEventIDs []EventID            `json:"applied_event_ids,omitempty"`
	Idempotency     map[string][]EventID `json:"idempotency,omitempty"`
}

func Reduce

func Reduce(state Snapshot, event Event) (Snapshot, error)

Reduce applies one event to a snapshot and returns the next snapshot. It is idempotent per event ID: replaying an already-applied event is a no-op. Events sharing a command's idempotency key are also deduplicated so a retried batch never double-applies.

func (Snapshot) MarshalJSON

func (snapshot Snapshot) MarshalJSON() ([]byte, error)

MarshalJSON guarantees that emitted snapshots can be strictly decoded.

func (*Snapshot) UnmarshalJSON

func (snapshot *Snapshot) UnmarshalJSON(data []byte) error

UnmarshalJSON preserves arbitrary-precision JSON numbers stored in metadata.

type StagedEvidence

type StagedEvidence struct {
	EvidenceID   EvidenceID
	OriginalPath string
	StoredPath   string
	Size         int64
	SHA256       string
}

StagedEvidence describes one artifact copied into an immutable evidence directory. OriginalPath is the caller's original source path; StoredPath is the path of the stored copy RELATIVE TO the instance directory (evidence/<id>/<storedName>).

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store applies commands to workflow instances under a single POSIX flock and durably persists a locked NDJSON event log plus an atomically replaced snapshot per instance.

func New

func New(root string) *Store

func (*Store) ApplyCommand

func (s *Store) ApplyCommand(workflowID WorkflowID, cmd Command) (Snapshot, error)

ApplyCommand applies one command under the instance's exclusive flock.

func (*Store) Catalog

func (s *Store) Catalog() ([]CatalogedInstance, error)

Catalog enumerates every recoverable instance under the root, replaying each instance's events beyond its snapshot revision and expiring stale leases. The per-instance restart-recovery work lives in recovery.go.

func (*Store) CreateRoot

func (s *Store) CreateRoot() error

CreateRoot ensures the on-disk directory layout exists: the configured workflow root, the templates directory, and the instances directory.

func (*Store) LoadTemplate

func (s *Store) LoadTemplate(templateID TemplateID, templateVersion TemplateVersion) (Template, error)

LoadTemplate reads a versioned template, returning a not-found error if it has not been stored.

func (*Store) Root

func (s *Store) Root() string

func (*Store) StageEvidence

func (s *Store) StageEvidence(workflowID WorkflowID, srcPath, storedName string, required bool, expectedSHA256 string) (StagedEvidence, error)

StageEvidence — public Store method (no workflow state transition).

func (*Store) StoreTemplate

func (s *Store) StoreTemplate(templateID TemplateID, templateVersion TemplateVersion, template Template) error

StoreTemplate atomically persists a versioned template under <root>/templates/<templateID>/<version>.json.

type Subject

type Subject struct {
	Type        string `json:"type"`
	Repository  string `json:"repository,omitempty"`
	PullRequest int    `json:"pull_request,omitempty"`
	Revision    string `json:"revision"`
}

type TeamAction

type TeamAction struct {
	TeamFile string `json:"team_file"`
}

type Template

type Template struct {
	SchemaVersion     int                     `json:"schema_version"`
	TemplateID        TemplateID              `json:"template_id"`
	TemplateVersion   TemplateVersion         `json:"template_version"`
	Metadata          map[string]any          `json:"metadata,omitempty"`
	EntryNodes        []NodeID                `json:"entry_nodes"`
	Nodes             []NodeDefinition        `json:"nodes"`
	TerminalOutcomes  []OutcomeName           `json:"terminal_outcomes"`
	BoundedLoops      []BoundedLoopDefinition `json:"bounded_loops,omitempty"`
	DefaultLease      *LeasePolicy            `json:"default_lease_policy,omitempty"`
	DefaultRetry      *RetryPolicy            `json:"default_retry_policy,omitempty"`
	CompositionLimits *CompositionLimits      `json:"composition_limits,omitempty"`
}

Template is an immutable, reusable workflow definition.

func (Template) MarshalJSON

func (template Template) MarshalJSON() ([]byte, error)

MarshalJSON guarantees that emitted templates satisfy the strict wire syntax.

func (*Template) UnmarshalJSON

func (template *Template) UnmarshalJSON(data []byte) error

UnmarshalJSON preserves arbitrary-precision JSON numbers stored in metadata.

type TemplateID

type TemplateID string

type TemplateOutputReference

type TemplateOutputReference struct {
	NodeID   NodeID   `json:"node_id"`
	OutputID OutputID `json:"output_id"`
}

TemplateOutputReference identifies an output available from a parent node. Runtime OutputReference values add workflow, activation, and revision identity.

type TemplateResolver

type TemplateResolver func(templateID TemplateID, templateVersion TemplateVersion) (Template, error)

TemplateResolver resolves a pinned child template. The manager provides the store-backed implementation; tests supply in-memory resolvers so the composition rules are unit-testable without a store.

type TemplateVersion

type TemplateVersion string

type Transition

type Transition struct {
	ActivationID ActivationID `json:"activation_id"`
	Outcome      OutcomeName  `json:"outcome"`
	TargetNodeID NodeID       `json:"target_node_id,omitempty"`
	CreatedAt    time.Time    `json:"created_at"`
}

type WorkflowAction

type WorkflowAction struct {
	TemplateID      TemplateID                  `json:"template_id"`
	TemplateVersion TemplateVersion             `json:"template_version"`
	ChildKey        string                      `json:"child_key"`
	InputBindings   []InputBinding              `json:"input_bindings,omitempty"`
	OutputBindings  []OutputBinding             `json:"output_bindings,omitempty"`
	OutcomeMap      map[OutcomeName]OutcomeName `json:"outcome_map"`
}

type WorkflowID

type WorkflowID string

func DeriveChildWorkflowID

func DeriveChildWorkflowID(parent WorkflowID, nodeID NodeID, childKey string) WorkflowID

DeriveChildWorkflowID deterministically derives the child workflow ID for a workflow-action node from the parent's identity. Re-instantiation or replay of the same parent therefore always targets the same child instance, which is what makes child creation idempotent: a second attempt finds the child under its derived ID and resumes it instead of creating a duplicate.

func NewWorkflowID

func NewWorkflowID() WorkflowID

type WorkflowInstance

type WorkflowInstance struct {
	WorkflowID      WorkflowID       `json:"workflow_id"`
	InstanceID      InstanceID       `json:"instance_id"`
	TemplateID      TemplateID       `json:"template_id"`
	TemplateVersion TemplateVersion  `json:"template_version"`
	Revision        int64            `json:"revision"`
	CreatedAt       time.Time        `json:"created_at"`
	UpdatedAt       time.Time        `json:"updated_at"`
	Metadata        map[string]any   `json:"metadata,omitempty"`
	Status          WorkflowStatus   `json:"status"`
	TerminalOutcome OutcomeName      `json:"terminal_outcome,omitempty"`
	Activations     []Activation     `json:"activations"`
	Attempts        []Attempt        `json:"attempts,omitempty"`
	Evidence        []Evidence       `json:"evidence,omitempty"`
	Gates           []GateInstance   `json:"gates,omitempty"`
	Outputs         []OutputValue    `json:"outputs,omitempty"`
	Children        []ChildReference `json:"children,omitempty"`
}

type WorkflowProfile

type WorkflowProfile struct {
	BoundedLoops       *[]WorkflowProfileBoundedLoop     "json:\"bounded_loops,omitempty\""
	CompositionLimits  *WorkflowProfileCompositionLimits "json:\"composition_limits,omitempty\""
	DefaultLeasePolicy *WorkflowProfileLeasePolicy       "json:\"default_lease_policy,omitempty\""
	DefaultRetryPolicy *WorkflowProfileRetryPolicy       "json:\"default_retry_policy,omitempty\""
	EntryNodes         []string                          "json:\"entry_nodes\""
	Metadata           *WorkflowProfileMetadata          "json:\"metadata,omitempty\""
	Nodes              []WorkflowProfileNode             "json:\"nodes\""
	SchemaVersion      int64                             "json:\"schema_version\""
	TemplateId         string                            "json:\"template_id\""
	TemplateVersion    string                            "json:\"template_version\""
	TerminalOutcomes   []string                          "json:\"terminal_outcomes\""
}

func (*WorkflowProfile) UnmarshalJSON

func (v *WorkflowProfile) UnmarshalJSON(data []byte) error

func (WorkflowProfile) Validate

func (v WorkflowProfile) Validate() []Issue

type WorkflowProfileAction

type WorkflowProfileAction struct {
	Value WorkflowProfileActionValue `json:"-"`
}

func (WorkflowProfileAction) MarshalJSON

func (u WorkflowProfileAction) MarshalJSON() ([]byte, error)

func (*WorkflowProfileAction) UnmarshalJSON

func (u *WorkflowProfileAction) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes WorkflowProfileAction by its "type" discriminator const.

type WorkflowProfileActionKind

type WorkflowProfileActionKind string
const (
	WorkflowProfileActionKindExternal WorkflowProfileActionKind = "external"
	WorkflowProfileActionKindLoop     WorkflowProfileActionKind = "loop"
	WorkflowProfileActionKindManual   WorkflowProfileActionKind = "manual"
	WorkflowProfileActionKindRun      WorkflowProfileActionKind = "run"
	WorkflowProfileActionKindTeam     WorkflowProfileActionKind = "team"
	WorkflowProfileActionKindWorkflow WorkflowProfileActionKind = "workflow"
)

type WorkflowProfileActionValue

type WorkflowProfileActionValue interface {
	// contains filtered or unexported methods
}

WorkflowProfileActionValue is the sealed branch value for WorkflowProfileAction.

type WorkflowProfileActionValueExternal

type WorkflowProfileActionValueExternal struct {
	Source      *string                   "json:\"source,omitempty\""
	SubjectType *string                   "json:\"subject_type,omitempty\""
	Type        WorkflowProfileActionKind "json:\"type\""
}

func (*WorkflowProfileActionValueExternal) UnmarshalJSON

func (v *WorkflowProfileActionValueExternal) UnmarshalJSON(data []byte) error

type WorkflowProfileActionValueLoop

type WorkflowProfileActionValueLoop struct {
	LoopFile *string                   "json:\"loop_file,omitempty\""
	Type     WorkflowProfileActionKind "json:\"type\""
}

func (*WorkflowProfileActionValueLoop) UnmarshalJSON

func (v *WorkflowProfileActionValueLoop) UnmarshalJSON(data []byte) error

type WorkflowProfileActionValueManual

type WorkflowProfileActionValueManual struct {
	Instructions *string                   "json:\"instructions,omitempty\""
	Type         WorkflowProfileActionKind "json:\"type\""
}

func (*WorkflowProfileActionValueManual) UnmarshalJSON

func (v *WorkflowProfileActionValueManual) UnmarshalJSON(data []byte) error

type WorkflowProfileActionValueRun

type WorkflowProfileActionValueRun struct {
	Prompt     *string                   "json:\"prompt,omitempty\""
	PromptFile *string                   "json:\"prompt_file,omitempty\""
	Type       WorkflowProfileActionKind "json:\"type\""
}

func (*WorkflowProfileActionValueRun) UnmarshalJSON

func (v *WorkflowProfileActionValueRun) UnmarshalJSON(data []byte) error

type WorkflowProfileActionValueTeam

type WorkflowProfileActionValueTeam struct {
	TeamFile *string                   "json:\"team_file,omitempty\""
	Type     WorkflowProfileActionKind "json:\"type\""
}

func (*WorkflowProfileActionValueTeam) UnmarshalJSON

func (v *WorkflowProfileActionValueTeam) UnmarshalJSON(data []byte) error

type WorkflowProfileActionValueWorkflow

type WorkflowProfileActionValueWorkflow struct {
	ChildKey        *string                                  "json:\"child_key,omitempty\""
	InputBindings   *[]WorkflowProfileInputBinding           "json:\"input_bindings,omitempty\""
	OutcomeMap      *WorkflowProfileActionWorkflowOutcomeMap "json:\"outcome_map,omitempty\""
	OutputBindings  *[]WorkflowProfileOutputBinding          "json:\"output_bindings,omitempty\""
	TemplateId      *string                                  "json:\"template_id,omitempty\""
	TemplateVersion *string                                  "json:\"template_version,omitempty\""
	Type            WorkflowProfileActionKind                "json:\"type\""
}

func (*WorkflowProfileActionValueWorkflow) UnmarshalJSON

func (v *WorkflowProfileActionValueWorkflow) UnmarshalJSON(data []byte) error

type WorkflowProfileActionWorkflowOutcomeMap

type WorkflowProfileActionWorkflowOutcomeMap struct {
}

func (*WorkflowProfileActionWorkflowOutcomeMap) UnmarshalJSON

func (v *WorkflowProfileActionWorkflowOutcomeMap) UnmarshalJSON(data []byte) error

type WorkflowProfileArtifactRequirement

type WorkflowProfileArtifactRequirement struct {
	NonEmpty *bool   "json:\"non_empty,omitempty\""
	Path     string  "json:\"path\""
	Sha256   *string "json:\"sha256,omitempty\""
}

func (*WorkflowProfileArtifactRequirement) UnmarshalJSON

func (v *WorkflowProfileArtifactRequirement) UnmarshalJSON(data []byte) error

type WorkflowProfileAssignment

type WorkflowProfileAssignment struct {
	Agent       *string "json:\"agent,omitempty\""
	Backend     *string "json:\"backend,omitempty\""
	Model       *string "json:\"model,omitempty\""
	Role        *string "json:\"role,omitempty\""
	RosterEntry *string "json:\"roster_entry,omitempty\""
	RosterFile  *string "json:\"roster_file,omitempty\""
	Thinking    *string "json:\"thinking,omitempty\""
}

func (*WorkflowProfileAssignment) UnmarshalJSON

func (v *WorkflowProfileAssignment) UnmarshalJSON(data []byte) error

type WorkflowProfileAuthorityRule

type WorkflowProfileAuthorityRule struct {
	Authorities    []string "json:\"authorities\""
	ReasonRequired *bool    "json:\"reason_required,omitempty\""
}

func (*WorkflowProfileAuthorityRule) UnmarshalJSON

func (v *WorkflowProfileAuthorityRule) UnmarshalJSON(data []byte) error

type WorkflowProfileAvailability

type WorkflowProfileAvailability struct {
	BoundedLoops       FieldStatus
	CompositionLimits  FieldStatus
	DefaultLeasePolicy FieldStatus
	DefaultRetryPolicy FieldStatus
	EntryNodes         FieldStatus
	Metadata           FieldStatus
	Nodes              FieldStatus
	SchemaVersion      FieldStatus
	TemplateId         FieldStatus
	TemplateVersion    FieldStatus
	TerminalOutcomes   FieldStatus
}

WorkflowProfileAvailability holds the availability status for each field.

type WorkflowProfileBoundedLoop

type WorkflowProfileBoundedLoop struct {
	BodyNodes         []string  "json:\"body_nodes\""
	CheckpointNodeId  string    "json:\"checkpoint_node_id\""
	EntryNodeId       string    "json:\"entry_node_id\""
	ExitOutcomes      *[]string "json:\"exit_outcomes,omitempty\""
	Id                string    "json:\"id\""
	MaximumIterations int64     "json:\"maximum_iterations\""
}

func (*WorkflowProfileBoundedLoop) UnmarshalJSON

func (v *WorkflowProfileBoundedLoop) UnmarshalJSON(data []byte) error

type WorkflowProfileCheckpoint

type WorkflowProfileCheckpoint struct {
	ExitOutcomes    *[]string "json:\"exit_outcomes,omitempty\""
	Path            string    "json:\"path\""
	RequiresRelease *bool     "json:\"requires_release,omitempty\""
}

func (*WorkflowProfileCheckpoint) UnmarshalJSON

func (v *WorkflowProfileCheckpoint) UnmarshalJSON(data []byte) error

type WorkflowProfileCompletion

type WorkflowProfileCompletion struct {
	Artifacts *[]WorkflowProfileArtifactRequirement "json:\"artifacts,omitempty\""
	Git       *WorkflowProfileGitRequirement        "json:\"git,omitempty\""
	Kind      string                                "json:\"kind\""
}

func (*WorkflowProfileCompletion) UnmarshalJSON

func (v *WorkflowProfileCompletion) UnmarshalJSON(data []byte) error

type WorkflowProfileCompositionLimits

type WorkflowProfileCompositionLimits struct {
	MaxChildren int64 "json:\"max_children\""
	MaxDepth    int64 "json:\"max_depth\""
}

func (*WorkflowProfileCompositionLimits) UnmarshalJSON

func (v *WorkflowProfileCompositionLimits) UnmarshalJSON(data []byte) error

type WorkflowProfileConditions

type WorkflowProfileConditions struct {
}

WorkflowProfileConditions holds the conditions for WorkflowProfile availability checks.

type WorkflowProfileFields

type WorkflowProfileFields struct {
	BoundedLoops       *[]WorkflowProfileBoundedLoop     "json:\"bounded_loops,omitempty\""
	CompositionLimits  *WorkflowProfileCompositionLimits "json:\"composition_limits,omitempty\""
	DefaultLeasePolicy *WorkflowProfileLeasePolicy       "json:\"default_lease_policy,omitempty\""
	DefaultRetryPolicy *WorkflowProfileRetryPolicy       "json:\"default_retry_policy,omitempty\""
	EntryNodes         *[]string                         "json:\"entry_nodes,omitempty\""
	Metadata           *WorkflowProfileMetadata          "json:\"metadata,omitempty\""
	Nodes              *[]WorkflowProfileNode            "json:\"nodes,omitempty\""
	SchemaVersion      *int64                            "json:\"schema_version,omitempty\""
	TemplateId         *string                           "json:\"template_id,omitempty\""
	TemplateVersion    *string                           "json:\"template_version,omitempty\""
	TerminalOutcomes   *[]string                         "json:\"terminal_outcomes,omitempty\""
}

WorkflowProfileFields holds the fields for WorkflowProfile availability checks.

func DecodeWorkflowProfile

func DecodeWorkflowProfile(data []byte) (WorkflowProfileFields, error)

DecodeWorkflowProfile validates raw JSON structurally, then decodes it into WorkflowProfileFields. If raw validation finds issues it returns a *WorkflowProfileStructuralError from which callers recover normalized issues via errors.As.

type WorkflowProfileGate

type WorkflowProfileGate struct {
	AllowedOutcomes *[]string "json:\"allowed_outcomes,omitempty\""
	Id              string    "json:\"id\""
	Name            *string   "json:\"name,omitempty\""
	Required        *bool     "json:\"required,omitempty\""
	SubjectType     *string   "json:\"subject_type,omitempty\""
	Type            string    "json:\"type\""
}

func (*WorkflowProfileGate) UnmarshalJSON

func (v *WorkflowProfileGate) UnmarshalJSON(data []byte) error

type WorkflowProfileGitRequirement

type WorkflowProfileGitRequirement struct {
	ChangedFromBase *bool   "json:\"changed_from_base,omitempty\""
	Clean           *bool   "json:\"clean,omitempty\""
	Head            *string "json:\"head,omitempty\""
}

func (*WorkflowProfileGitRequirement) UnmarshalJSON

func (v *WorkflowProfileGitRequirement) UnmarshalJSON(data []byte) error

type WorkflowProfileInputBinding

type WorkflowProfileInputBinding struct {
	From  *WorkflowProfileTemplateOutputRef "json:\"from,omitempty\""
	Input string                            "json:\"input\""
	Value *WorkflowProfileInputBindingValue "json:\"value,omitempty\""
}

func (*WorkflowProfileInputBinding) UnmarshalJSON

func (v *WorkflowProfileInputBinding) UnmarshalJSON(data []byte) error

type WorkflowProfileInputBindingValue

type WorkflowProfileInputBindingValue struct {
}

func (*WorkflowProfileInputBindingValue) UnmarshalJSON

func (v *WorkflowProfileInputBindingValue) UnmarshalJSON(data []byte) error

type WorkflowProfileLeasePolicy

type WorkflowProfileLeasePolicy struct {
	HeartbeatIntervalSeconds *int64 "json:\"heartbeat_interval_seconds,omitempty\""
	TtlSeconds               int64  "json:\"ttl_seconds\""
}

func (*WorkflowProfileLeasePolicy) UnmarshalJSON

func (v *WorkflowProfileLeasePolicy) UnmarshalJSON(data []byte) error

type WorkflowProfileMetadata

type WorkflowProfileMetadata struct {
}

func (*WorkflowProfileMetadata) UnmarshalJSON

func (v *WorkflowProfileMetadata) UnmarshalJSON(data []byte) error

type WorkflowProfileNode

type WorkflowProfileNode struct {
	Action       WorkflowProfileAction           "json:\"action\""
	Assignment   *WorkflowProfileAssignment      "json:\"assignment,omitempty\""
	Branches     *WorkflowProfileNodeBranches    "json:\"branches,omitempty\""
	Checkpoint   *WorkflowProfileCheckpoint      "json:\"checkpoint,omitempty\""
	Completion   *WorkflowProfileCompletion      "json:\"completion,omitempty\""
	Dependencies *[]string                       "json:\"dependencies,omitempty\""
	Gates        *[]WorkflowProfileGate          "json:\"gates,omitempty\""
	Id           string                          "json:\"id\""
	LeasePolicy  *WorkflowProfileLeasePolicy     "json:\"lease_policy,omitempty\""
	LoopId       *string                         "json:\"loop_id,omitempty\""
	Name         *string                         "json:\"name,omitempty\""
	Outcomes     *[]WorkflowProfileOutcome       "json:\"outcomes,omitempty\""
	Outputs      *[]WorkflowProfileOutput        "json:\"outputs,omitempty\""
	RetryPolicy  *WorkflowProfileRetryPolicy     "json:\"retry_policy,omitempty\""
	SkipRule     *WorkflowProfileAuthorityRule   "json:\"skip_rule,omitempty\""
	WaiveRules   *[]WorkflowProfileAuthorityRule "json:\"waive_rules,omitempty\""
}

func (*WorkflowProfileNode) UnmarshalJSON

func (v *WorkflowProfileNode) UnmarshalJSON(data []byte) error

type WorkflowProfileNodeBranches

type WorkflowProfileNodeBranches struct {
}

func (*WorkflowProfileNodeBranches) UnmarshalJSON

func (v *WorkflowProfileNodeBranches) UnmarshalJSON(data []byte) error

type WorkflowProfileOutcome

type WorkflowProfileOutcome struct {
	Name         string  "json:\"name\""
	TargetNodeId *string "json:\"target_node_id,omitempty\""
	Terminal     *bool   "json:\"terminal,omitempty\""
}

func (*WorkflowProfileOutcome) UnmarshalJSON

func (v *WorkflowProfileOutcome) UnmarshalJSON(data []byte) error

type WorkflowProfileOutput

type WorkflowProfileOutput struct {
	Id       string "json:\"id\""
	Name     string "json:\"name\""
	Required *bool  "json:\"required,omitempty\""
	Type     string "json:\"type\""
}

func (*WorkflowProfileOutput) UnmarshalJSON

func (v *WorkflowProfileOutput) UnmarshalJSON(data []byte) error

type WorkflowProfileOutputBinding

type WorkflowProfileOutputBinding struct {
	ChildOutput  string "json:\"child_output\""
	ParentOutput string "json:\"parent_output\""
}

func (*WorkflowProfileOutputBinding) UnmarshalJSON

func (v *WorkflowProfileOutputBinding) UnmarshalJSON(data []byte) error

type WorkflowProfileRetryPolicy

type WorkflowProfileRetryPolicy struct {
	Exhaustion  string  "json:\"exhaustion\""
	MaxAttempts int64   "json:\"max_attempts\""
	Outcome     *string "json:\"outcome,omitempty\""
}

func (*WorkflowProfileRetryPolicy) UnmarshalJSON

func (v *WorkflowProfileRetryPolicy) UnmarshalJSON(data []byte) error

type WorkflowProfileStructuralError

type WorkflowProfileStructuralError struct {
	Issues []WorkflowProfileStructuralIssue
}

WorkflowProfileStructuralError carries normalized structural issues from Decode.

func (*WorkflowProfileStructuralError) Error

type WorkflowProfileStructuralIssue

type WorkflowProfileStructuralIssue struct {
	Source     string
	Code       string
	Path       string
	SchemaPath string
	Message    string
}

WorkflowProfileStructuralIssue describes one structural validation problem.

func ValidateWorkflowProfileJSON

func ValidateWorkflowProfileJSON(data []byte) ([]WorkflowProfileStructuralIssue, error)

ValidateWorkflowProfileJSON validates raw JSON and returns normalized structural issues. It returns a non-nil error only for malformed JSON or trailing JSON values; well-formed but structurally invalid input yields issues.

func WorkflowProfileStructuralIssueAt

func WorkflowProfileStructuralIssueAt(code, path, schemaPath string) WorkflowProfileStructuralIssue

WorkflowProfileStructuralIssueAt builds a normalized json-schema issue.

func WorkflowProfileStructuralSort

func WorkflowProfileStructuralSort(issues []WorkflowProfileStructuralIssue) []WorkflowProfileStructuralIssue

WorkflowProfileStructuralSort dedupes issues by (source, code, path) and sorts by path, then code.

type WorkflowProfileTemplateOutputRef

type WorkflowProfileTemplateOutputRef struct {
	NodeId   string "json:\"node_id\""
	OutputId string "json:\"output_id\""
}

func (*WorkflowProfileTemplateOutputRef) UnmarshalJSON

func (v *WorkflowProfileTemplateOutputRef) UnmarshalJSON(data []byte) error

type WorkflowStatus

type WorkflowStatus string

WorkflowStatus is the durable status of a workflow instance.

const (
	WorkflowActive       WorkflowStatus = "active"
	WorkflowBlocked      WorkflowStatus = "blocked"
	WorkflowAwaitingGate WorkflowStatus = "awaiting_gate"
	WorkflowCompleted    WorkflowStatus = "completed"
	WorkflowFailed       WorkflowStatus = "failed"
	WorkflowCanceled     WorkflowStatus = "canceled"
)

Jump to

Keyboard shortcuts

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