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
- func ProjectExecutionMD(snap Snapshot, nodeID NodeID) string
- func ProjectReviewMD(snap Snapshot, gi GateInstance) string
- func ProjectWorkflowMD(snap Snapshot) string
- func SetCompletionGateResolver(...)
- func SetRetryPolicyResolver(...)
- func ValidateGraph(template Template) error
- func ValidateTemplate(template Template) error
- func ValidateTemplateJSON(data []byte) error
- func WorkflowProfileStructuralIntParts(raw json.RawMessage) (val int64, isInt, safe bool)
- func WorkflowProfileStructuralKind(raw json.RawMessage) string
- func WriteProjections(dir string, snap Snapshot) error
- type Action
- type ActionKind
- type Activation
- type ActivationID
- type ActivationStatus
- type ArtifactRequirement
- type Assignment
- type Attempt
- type AttemptID
- type AttemptStatus
- type AuthorityRule
- type BoundedLoopDefinition
- type CatalogedInstance
- type ChallengeResult
- type CheckpointDefinition
- type ChildReference
- type ChildReferenceID
- type Command
- type CommandID
- type CommandKind
- type CompletionContract
- type CompletionContractKind
- type Composition
- type CompositionChild
- type CompositionLimits
- type Event
- type EventID
- type EventKind
- type Evidence
- type EvidenceID
- type EvidenceSource
- type ExecutionIdentity
- type ExecutionSelection
- type Executor
- type ExecutorContext
- type ExternalAction
- type FieldStatus
- type GateDefinition
- type GateID
- type GateInstance
- type GateInstanceID
- type GateOperation
- type GateStatus
- type GateType
- type GitRequirement
- type InputBinding
- type InstanceID
- type InstanceRecord
- type Issue
- type Lease
- type LeaseExpirySummary
- type LeaseID
- type LeasePolicy
- type LoopAction
- type LoopID
- type Manager
- func (m *Manager) ExpireStaleLeases() (LeaseExpirySummary, error)
- func (m *Manager) Heartbeat(wf WorkflowID, nodeID NodeID, activationID ActivationID, leaseID LeaseID, ...) error
- func (m *Manager) RecordAttemptTerminated(wf WorkflowID, nodeID NodeID, activationID ActivationID, attemptID AttemptID, ...) error
- func (m *Manager) RegisterExecutor(kind ActionKind, exec Executor)
- func (m *Manager) ResumeAwaitingChildren() (ResumeAwaitingChildrenSummary, error)
- func (m *Manager) WorkflowCommand(id string, payload json.RawMessage) (any, error)
- func (m *Manager) WorkflowCreate(payload json.RawMessage) (any, error)
- func (m *Manager) WorkflowEvents(id string, afterSeq int64, limit int) (any, error)
- func (m *Manager) WorkflowInspect(id string) (any, error)
- func (m *Manager) WorkflowInstantiate(payload json.RawMessage) (any, error)
- func (m *Manager) WorkflowStatus(id string) (any, error)
- func (m *Manager) WorkflowWait(id string, timeout time.Duration) (any, error)
- type ManualAction
- type NodeDefinition
- type NodeID
- type OutcomeDefinition
- type OutcomeName
- type OutputBinding
- type OutputDefinition
- type OutputID
- type OutputReference
- type OutputType
- type OutputValue
- type ResumeAwaitingChildrenSummary
- type RetryExhaustionKind
- type RetryPolicy
- type RuleMetaEntry
- type RunAction
- type Snapshot
- type StagedEvidence
- type Store
- func (s *Store) ApplyCommand(workflowID WorkflowID, cmd Command) (Snapshot, error)
- func (s *Store) Catalog() ([]CatalogedInstance, error)
- func (s *Store) CreateRoot() error
- func (s *Store) LoadTemplate(templateID TemplateID, templateVersion TemplateVersion) (Template, error)
- func (s *Store) Root() string
- func (s *Store) StageEvidence(workflowID WorkflowID, srcPath, storedName string, required bool, ...) (StagedEvidence, error)
- func (s *Store) StoreTemplate(templateID TemplateID, templateVersion TemplateVersion, template Template) error
- type Subject
- type TeamAction
- type Template
- type TemplateID
- type TemplateOutputReference
- type TemplateResolver
- type TemplateVersion
- type Transition
- type WorkflowAction
- type WorkflowID
- type WorkflowInstance
- type WorkflowProfile
- type WorkflowProfileAction
- type WorkflowProfileActionKind
- type WorkflowProfileActionValue
- type WorkflowProfileActionValueExternal
- type WorkflowProfileActionValueLoop
- type WorkflowProfileActionValueManual
- type WorkflowProfileActionValueRun
- type WorkflowProfileActionValueTeam
- type WorkflowProfileActionValueWorkflow
- type WorkflowProfileActionWorkflowOutcomeMap
- type WorkflowProfileArtifactRequirement
- type WorkflowProfileAssignment
- type WorkflowProfileAuthorityRule
- type WorkflowProfileAvailability
- type WorkflowProfileBoundedLoop
- type WorkflowProfileCheckpoint
- type WorkflowProfileCompletion
- type WorkflowProfileCompositionLimits
- type WorkflowProfileConditions
- type WorkflowProfileFields
- type WorkflowProfileGate
- type WorkflowProfileGitRequirement
- type WorkflowProfileInputBinding
- type WorkflowProfileInputBindingValue
- type WorkflowProfileLeasePolicy
- type WorkflowProfileMetadata
- type WorkflowProfileNode
- type WorkflowProfileNodeBranches
- type WorkflowProfileOutcome
- type WorkflowProfileOutput
- type WorkflowProfileOutputBinding
- type WorkflowProfileRetryPolicy
- type WorkflowProfileStructuralError
- type WorkflowProfileStructuralIssue
- type WorkflowProfileTemplateOutputRef
- type WorkflowStatus
Constants ¶
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.
const DefaultHeartbeatInterval = 10 * time.Second
DefaultHeartbeatInterval is the advisory heartbeat cadence used when no policy declares one.
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 ¶
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 ¶
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 ¶
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 ¶
ValidateTemplate evaluates the generated portable Umpire contract and the typed structural checks. Stage 3 adds graph- and context-dependent rules.
func ValidateTemplateJSON ¶
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 ¶
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) UnmarshalJSON ¶
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 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 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 BoundedLoopDefinition ¶
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.
func Challenge ¶
func Challenge(fieldName string, f WorkflowProfileFields, c WorkflowProfileConditions, prev WorkflowProfileFields) ChallengeResult
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 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 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 ¶
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 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 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 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 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 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.
type GitRequirement ¶
type InputBinding ¶
type InputBinding struct {
Input string `json:"input"`
Value json.RawMessage `json:"value,omitempty"`
From *TemplateOutputReference `json:"from,omitempty"`
}
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 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 LeasePolicy ¶
type LoopAction ¶
type LoopAction struct {
LoopFile string `json:"loop_file"`
}
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
func NewManager ¶
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 ¶
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 ¶
WorkflowEvents returns log events with Sequence > afterSeq, capped at limit (limit <= 0 caps at 1000).
func (*Manager) WorkflowInspect ¶
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 ¶
WorkflowStatus returns a compact status view of a workflow instance.
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 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 OutputDefinition ¶
type OutputDefinition struct {
ID OutputID `json:"id"`
Name string `json:"name"`
Type OutputType `json:"type"`
Required bool `json:"required,omitempty"`
}
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 ¶
RuleMetaEntry holds metadata about a rule for Challenge output.
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 ¶
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 ¶
MarshalJSON guarantees that emitted snapshots can be strictly decoded.
func (*Snapshot) UnmarshalJSON ¶
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 (*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 ¶
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) 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 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 ¶
MarshalJSON guarantees that emitted templates satisfy the strict wire syntax.
func (*Template) UnmarshalJSON ¶
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.
func Check ¶
func Check(f WorkflowProfileFields, c WorkflowProfileConditions, prev WorkflowProfileFields) WorkflowProfileAvailability
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 ¶
func (e *WorkflowProfileStructuralError) Error() string
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" )