Documentation
¶
Overview ¶
Package projectdurable hosts the go-workflows durable execution pilot.
Pilot boundary (see .ai/tasks/go-workflows-durable-automation-pilot/IMPLEMENTATION_PLAN.md): nothing in this package is wired into production paths. Durable workflow history must contain safe refs and bounded metadata only - never raw prompts, completions, stderr, source dumps, provider payloads, secrets, roots, external URLs, or PII.
Index ¶
- Constants
- Variables
- func ValidateSafeRef(ref string) error
- func ValidateSafeSummary(s string) error
- type AttemptCompletionPort
- type AutomationRunObserver
- type ChainPipelinePort
- type ChainRunComparator
- type ChainStageObserver
- type DurableActivityResult
- type DurableAttemptOutcome
- type DurableFailureCategory
- type DurableIntakeRequest
- type DurableIntakeResult
- type DurableRunSnapshot
- type Engine
- type InMemoryRunnerShadowRecorder
- type IntakeKind
- type RunnerShadowEvent
- type RunnerShadowRecorder
- type SafeAutomationRunRef
- type SafeChainStagePlan
- type SafeStageCompileOutcome
- type SafeStageSnapshot
- type SafeTaskSnapshot
- type SafeWorkTaskRef
- type SafeWorkflowStageRef
- type ShadowComparisonWriter
- type WorkTaskClaimPort
- type WorkTaskObserver
Constants ¶
const ( ActivityStatusOK = "ok" ActivityStatusBlocked = "blocked" ActivityStatusFailed = "failed" ActivityStatusSkipped = "skipped" )
Activity result statuses recorded by durable activities.
const ( RunnerShadowBoundaryClaimStarted = "runner_claim_started" RunnerShadowBoundaryClaimed = "runner_claimed" RunnerShadowBoundaryHeartbeatStarted = "runner_heartbeat_started" RunnerShadowBoundaryExecuteStarted = "runner_execute_started" RunnerShadowBoundaryExecuteFinished = "runner_execute_finished" RunnerShadowBoundaryCloseoutFinished = "runner_closeout_finished" RunnerShadowBoundaryReported = "runner_reported" )
Runner shadow boundaries are runner-side observations of the current authoritative claim/heartbeat/execute/report loop. They are metadata-only and must never drive current automation state.
Variables ¶
var ErrInvalidIntake = errors.New("invalid durable intake")
ErrInvalidIntake marks rejected durable intake input. Error messages name the violated rule only - never the submitted objective text or any substring of it.
var ErrUnsafeMetadata = errors.New("unsafe durable metadata")
ErrUnsafeMetadata marks metadata that failed the local safe-ref or safe-summary checks. Error messages name the violated rule, never the offending content.
Functions ¶
func ValidateSafeRef ¶
ValidateSafeRef applies small local checks to a single ref: non-empty, at most 200 chars, no control characters or whitespace.
func ValidateSafeSummary ¶
ValidateSafeSummary applies small local checks to a bounded summary: empty is allowed, at most 512 chars, single line (no control characters).
Types ¶
type AttemptCompletionPort ¶
type AttemptCompletionPort interface {
CompleteAttempt(ctx context.Context, ref SafeAutomationRunRef, outcome DurableAttemptOutcome) (DurableRunSnapshot, error)
}
AttemptCompletionPort reports one attempt outcome for the referenced run and returns the post-completion run snapshot. Test adapters implement it over the current service's CompleteAttempt and must return metadata only.
type AutomationRunObserver ¶
type AutomationRunObserver interface {
LoadRunSnapshot(ctx context.Context, ref SafeAutomationRunRef) (DurableRunSnapshot, error)
}
AutomationRunObserver loads a metadata-only snapshot of an automation run. Implementations live beside the projectautomation service; they must return only ids, refs, statuses, counters, and bounded safe summaries.
type ChainPipelinePort ¶
type ChainPipelinePort interface {
ResolveChainStages(ctx context.Context, projectID, chainRef string) ([]SafeChainStagePlan, error)
CompileStage(ctx context.Context, projectID, chainRef string, stage SafeChainStagePlan, inputRef string, carriedTaskIDs []string) (SafeStageCompileOutcome, error)
ReleaseCompiledTasks(ctx context.Context, planID string) error
ActivateWorkPlan(ctx context.Context, planID string) error
ObserveStagePlanStatus(ctx context.Context, planID string) (status string, taskStatuses map[string]string, err error)
CarryForwardOutputs(ctx context.Context, fromPlanID, toStageRef string) (concreteTaskIDs []string, err error)
ObserveGitOps(ctx context.Context, chainRef string) (gitOpsReady bool, prRef string, recoveryStatus string, blockedReason string, metadata map[string]string, err error)
}
ChainPipelinePort is the cohesive metadata-only port used by the Phase 5 workflow-chain shadow. Implementations are test adapters over the CURRENT workflow, work-plan, automation, and workflow-chain services until cutover approval. CompileStage must be compile-or-get idempotent for the tuple (project_id, chain_ref, stage_ref) so durable resume never duplicates current-system state.
type ChainRunComparator ¶
type ChainRunComparator interface {
LoadCurrentChainRun(ctx context.Context, projectID, chainRef string) (fields map[string]string, found bool, err error)
}
ChainRunComparator loads the current workflow-chain run read model as safe comparison fields. It is separate from ChainPipelinePort so tests can prove comparison-last behavior even when no current chain run exists.
type ChainStageObserver ¶
type ChainStageObserver interface {
LoadStageStatus(ctx context.Context, ref SafeWorkflowStageRef) (SafeStageSnapshot, error)
}
ChainStageObserver loads a metadata-only snapshot of a workflow chain stage. Implementations live beside the projectworkflowchain service; they must return only ids, refs, statuses, and bounded safe summaries.
type DurableActivityResult ¶
type DurableActivityResult struct {
Activity string `json:"activity"`
Status string `json:"status"`
FailureCategory DurableFailureCategory `json:"failure_category,omitempty"`
SafeSummary string `json:"safe_summary,omitempty"`
Refs []string `json:"refs,omitempty"`
CompletedAt time.Time `json:"completed_at"`
}
DurableActivityResult is the metadata-only outcome of one durable activity.
func (DurableActivityResult) Validate ¶
func (r DurableActivityResult) Validate() error
Validate applies the local safe-ref and safe-summary rules to every field and restricts Status to the small activity status set.
type DurableAttemptOutcome ¶
type DurableAttemptOutcome struct {
Status string `json:"status"`
ClaimID string `json:"claim_id,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
FailureCategory DurableFailureCategory `json:"failure_category,omitempty"`
SafeSummary string `json:"safe_summary,omitempty"`
EvidenceRefs []string `json:"evidence_refs,omitempty"`
VerifierResultRefs []string `json:"verifier_result_refs,omitempty"`
ReviewResultRefs []string `json:"review_result_refs,omitempty"`
ClaimRefs []string `json:"claim_refs,omitempty"`
KnowledgeCandidateRefs []string `json:"knowledge_candidate_refs,omitempty"`
}
DurableAttemptOutcome is the metadata-only completion report a durable activity hands to the AttemptCompletionPort. It mirrors the safe subset of the current CompleteAttemptInput contract (status, claim/runner ids, safe failure category, bounded summary, ref lists) without importing it.
func (DurableAttemptOutcome) Validate ¶
func (o DurableAttemptOutcome) Validate() error
Validate applies the local safe-ref and safe-summary rules to every field, fail-closed: an outcome that does not validate must never reach a port.
type DurableFailureCategory ¶
type DurableFailureCategory string
DurableFailureCategory is a bounded, safe failure label recorded in durable history. Values mirror the safe categories the current automation system already emits (see internal/projectautomation: RunStatus* statuses used as failure categories in service.go and safeCodexFailureCategory in codexcli.go). Only the small set needed by the shadow phases is mirrored.
const ( // FailureCategoryNone is the empty category for successful observations. FailureCategoryNone DurableFailureCategory = "" // FailureCategoryTimeout mirrors projectautomation.RunStatusTimeout. FailureCategoryTimeout DurableFailureCategory = "timeout" FailureCategoryRunnerUnavailable DurableFailureCategory = "runner_unavailable" // FailureCategoryPolicyDenied mirrors projectautomation.RunStatusPolicyDenied. FailureCategoryPolicyDenied DurableFailureCategory = "policy_denied" // FailureCategoryExternalRunnerInterrupted mirrors the // "external_runner_interrupted" category set by the automation service // for abandoned external runs. FailureCategoryExternalRunnerInterrupted DurableFailureCategory = "external_runner_interrupted" // FailureCategoryVerificationRequired mirrors the // "verification_required" category set when a run parks in verifying. FailureCategoryVerificationRequired DurableFailureCategory = "verification_required" FailureCategoryCodexAuthUnavailable DurableFailureCategory = "codex_auth_unavailable" // FailureCategoryCodexOutputSchemaInvalid mirrors safeCodexFailureCategory. FailureCategoryCodexOutputSchemaInvalid DurableFailureCategory = "codex_output_schema_invalid" // FailureCategoryCodexUsageLimitReached mirrors safeCodexFailureCategory. FailureCategoryCodexUsageLimitReached DurableFailureCategory = "codex_usage_limit_reached" // FailureCategoryCodexConfigUnreadable mirrors safeCodexFailureCategory. FailureCategoryCodexConfigUnreadable DurableFailureCategory = "codex_config_unreadable" )
func (DurableFailureCategory) Validate ¶
func (c DurableFailureCategory) Validate() error
Validate fails closed: only the mirrored known categories (or none) are accepted into durable history.
type DurableIntakeRequest ¶
type DurableIntakeRequest struct {
ProjectID string `json:"project_id"`
Kind IntakeKind `json:"kind"`
// TicketKey is the Jira issue key for IntakeKindJiraIssueKey, e.g.
// "PROJ-1044" or "jira:PROJ-1044".
TicketKey string `json:"ticket_key,omitempty"`
// ObjectiveText is the raw objective for IntakeKindObjectiveText.
// Excluded from JSON on purpose: raw prose must never reach durable
// history, stores, logs, or traces.
ObjectiveText string `json:"-"`
// ObjectiveTitleHint is an optional bounded safe summary supplied by
// the caller. It must not be derived from ObjectiveText content.
ObjectiveTitleHint string `json:"objective_title_hint,omitempty"`
}
DurableIntakeRequest is the V2 governed intake input. ObjectiveText is transient: it is consumed by NormalizeIntake to derive a deterministic safe ref and must NEVER be persisted, serialized, logged, or echoed in errors - hence the json:"-" tag. Everything else is metadata.
type DurableIntakeResult ¶
type DurableIntakeResult struct {
ProjectID string `json:"project_id"`
Kind IntakeKind `json:"kind"`
InputRef string `json:"input_ref"`
SafeSummary string `json:"safe_summary"`
ContextRefs []string `json:"context_refs,omitempty"`
}
DurableIntakeResult is the metadata-only outcome of governed intake.
func NormalizeIntake ¶
func NormalizeIntake(req DurableIntakeRequest) (DurableIntakeResult, error)
NormalizeIntake validates a governed intake request and produces the deterministic metadata-only result. Jira mode accepts "PROJ-1044" or "jira:PROJ-1044" and rejects fake prefixes such as "ticket:PROJ-1044". Objective mode hashes a normalized form of the text into "objective:<12 hex>" and never copies any substring of the text into the result or into error messages. Objective fields set in jira mode (and the ticket key set in objective mode) are rejected to fail closed.
type DurableRunSnapshot ¶
type DurableRunSnapshot struct {
Run SafeAutomationRunRef `json:"run"`
Status string `json:"status"`
FailureCategory DurableFailureCategory `json:"failure_category,omitempty"`
SafeSummary string `json:"safe_summary,omitempty"`
AttemptCount int `json:"attempt_count"`
ClaimID string `json:"claim_id,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
VerifierResultRefs []string `json:"verifier_result_refs,omitempty"`
ReviewResultRefs []string `json:"review_result_refs,omitempty"`
EvidenceRefs []string `json:"evidence_refs,omitempty"`
ClaimRefs []string `json:"claim_refs,omitempty"`
KnowledgeCandidateRefs []string `json:"knowledge_candidate_refs,omitempty"`
ObservedAt time.Time `json:"observed_at"`
}
DurableRunSnapshot is a metadata-only observation of an automation run. It carries ids, refs, statuses, counters, a bounded safe summary, and a timestamp - never prompts, completions, stderr, source, roots, or secrets.
func (DurableRunSnapshot) Validate ¶
func (s DurableRunSnapshot) Validate() error
Validate applies the local safe-ref and safe-summary rules to every field.
type Engine ¶
type Engine struct {
// Backend is the durable history store. Memory engines use an
// ephemeral in-memory SQLite backend.
Backend backend.Backend
// Orchestrator combines worker and client for single-process use.
Orchestrator *worker.WorkflowOrchestrator
}
Engine is a minimal wrapper around a go-workflows orchestrator. It exists so pilot tests construct durable execution through one seam instead of touching backend/worker wiring directly. No production code may construct an Engine while the pilot is disabled.
func NewMemoryEngine ¶
func NewMemoryEngine() *Engine
NewMemoryEngine returns an Engine backed by an ephemeral in-memory store. Test and local pilot use only; state is lost on Close.
func NewSQLiteEngine ¶
NewSQLiteEngine returns an Engine backed by a safe repo-local SQLite file. It does not start workers; callers must explicitly start the orchestrator.
type InMemoryRunnerShadowRecorder ¶
type InMemoryRunnerShadowRecorder struct {
// contains filtered or unexported fields
}
InMemoryRunnerShadowRecorder is a local test/pilot recorder. It validates and stores copies of metadata-only events.
func NewInMemoryRunnerShadowRecorder ¶
func NewInMemoryRunnerShadowRecorder() *InMemoryRunnerShadowRecorder
func (*InMemoryRunnerShadowRecorder) Events ¶
func (r *InMemoryRunnerShadowRecorder) Events() []RunnerShadowEvent
func (*InMemoryRunnerShadowRecorder) RecordRunnerShadowEvent ¶
func (r *InMemoryRunnerShadowRecorder) RecordRunnerShadowEvent(ctx context.Context, event RunnerShadowEvent) error
type IntakeKind ¶
type IntakeKind string
IntakeKind selects the V2 governed intake route.
const ( // IntakeKindJiraIssueKey routes intake through a Jira issue key. IntakeKindJiraIssueKey IntakeKind = "jira_issue_key" // IntakeKindObjectiveText routes intake through free-form objective // text that is hashed into a deterministic safe ref and never persisted. IntakeKindObjectiveText IntakeKind = "objective_text" )
type RunnerShadowEvent ¶
type RunnerShadowEvent struct {
Boundary string `json:"boundary"`
ProjectID string `json:"project_id,omitempty"`
Run SafeAutomationRunRef `json:"run"`
Status string `json:"status,omitempty"`
FailureCategory string `json:"failure_category,omitempty"`
SafeSummary string `json:"safe_summary,omitempty"`
AttemptCount int `json:"attempt_count"`
ClaimID string `json:"claim_id,omitempty"`
RunnerID string `json:"runner_id,omitempty"`
EvidenceRefs []string `json:"evidence_refs,omitempty"`
ObservedAt time.Time `json:"observed_at"`
}
RunnerShadowEvent is the safe runner-side metadata recorded in shadow mode. It intentionally excludes prompts, completions, stderr, source, filesystem roots, provider payloads, secrets, external URLs, and PII.
func (RunnerShadowEvent) Validate ¶
func (e RunnerShadowEvent) Validate() error
Validate fails closed for all runner shadow metadata.
type RunnerShadowRecorder ¶
type RunnerShadowRecorder interface {
RecordRunnerShadowEvent(ctx context.Context, event RunnerShadowEvent) error
}
RunnerShadowRecorder records runner shadow events. Implementations are optional while shadow mode is true; their failures must not affect the authoritative runner path.
type SafeAutomationRunRef ¶
type SafeAutomationRunRef struct {
ProjectID string `json:"project_id"`
AutomationID string `json:"automation_id"`
RunID string `json:"run_id"`
TaskID string `json:"task_id,omitempty"`
TraceID string `json:"trace_id,omitempty"`
}
SafeAutomationRunRef identifies an automation run by ids only.
func (SafeAutomationRunRef) Validate ¶
func (r SafeAutomationRunRef) Validate() error
Validate checks every field with the local safe-ref rules. TaskID and TraceID are optional and validated only when set.
type SafeChainStagePlan ¶
type SafeChainStagePlan struct {
StageRef string `json:"stage_ref"`
WorkflowRef string `json:"workflow_ref"`
}
SafeChainStagePlan is the metadata-only stage descriptor a durable chain workflow may consume. Production durable code knows only stage/workflow refs; test adapters resolve these from the current workflow-chain config.
func (SafeChainStagePlan) Validate ¶
func (p SafeChainStagePlan) Validate() error
Validate checks both refs fail-closed.
type SafeStageCompileOutcome ¶
type SafeStageCompileOutcome struct {
PlanID string `json:"plan_id"`
TaskIDs []string `json:"task_ids,omitempty"`
ReviewerTaskIDs []string `json:"reviewer_task_ids,omitempty"`
AutomationIDs []string `json:"automation_ids,omitempty"`
PermissionSnapshotIDs []string `json:"permission_snapshot_ids,omitempty"`
ContextRefs []string `json:"context_refs,omitempty"`
}
SafeStageCompileOutcome is the metadata-only result of compiling one chain stage. Test adapters implement compile-or-get idempotency: when a stage has already been compiled for the same chain ref, CompileStage returns the existing outcome instead of creating duplicate Work Plans, tasks, automations, or permission snapshots.
func (SafeStageCompileOutcome) Validate ¶
func (o SafeStageCompileOutcome) Validate() error
Validate applies safe-ref checks to the plan id and every returned ref.
type SafeStageSnapshot ¶
type SafeStageSnapshot struct {
Ref SafeWorkflowStageRef `json:"ref"`
Status string `json:"status"`
BlockedReason string `json:"blocked_reason,omitempty"`
NextAction string `json:"next_action,omitempty"`
}
SafeStageSnapshot is the metadata-only view of a workflow chain stage that durable activities are allowed to observe. BlockedReason and NextAction must pass ValidateSafeSummary.
type SafeTaskSnapshot ¶
type SafeTaskSnapshot struct {
Ref SafeWorkTaskRef `json:"ref"`
Status string `json:"status"`
Refs map[string][]string `json:"refs,omitempty"`
}
SafeTaskSnapshot is the metadata-only view of a work task that durable activities are allowed to observe. Refs groups ref slices by kind (for example "evidence_refs", "verifier_result_refs"); every key and every entry must pass ValidateSafeRef.
type SafeWorkTaskRef ¶
type SafeWorkTaskRef struct {
ProjectID string `json:"project_id"`
PlanID string `json:"plan_id"`
TaskID string `json:"task_id"`
TaskRef string `json:"task_ref,omitempty"`
}
SafeWorkTaskRef identifies a work task by ids only.
func (SafeWorkTaskRef) Validate ¶
func (r SafeWorkTaskRef) Validate() error
Validate checks every field with the local safe-ref rules. TaskRef is optional and validated only when set.
type SafeWorkflowStageRef ¶
type SafeWorkflowStageRef struct {
ProjectID string `json:"project_id"`
ChainRunID string `json:"chain_run_id"`
StageRef string `json:"stage_ref"`
WorkflowRef string `json:"workflow_ref"`
StageIndex int `json:"stage_index"`
}
SafeWorkflowStageRef identifies one stage of a workflow chain run.
func (SafeWorkflowStageRef) Validate ¶
func (r SafeWorkflowStageRef) Validate() error
Validate checks every field with the local safe-ref rules.
type ShadowComparisonWriter ¶
type ShadowComparisonWriter interface {
WriteShadowComparison(ctx context.Context, runRef SafeAutomationRunRef, fields map[string]string) error
}
ShadowComparisonWriter records shadow-mode comparison fields for one automation run. Every value in fields must pass ValidateSafeSummary (and keys must pass ValidateSafeRef); implementations live beside the current services and must reject anything else fail-closed.
type WorkTaskClaimPort ¶
type WorkTaskClaimPort interface {
ClaimRun(ctx context.Context, ref SafeAutomationRunRef, runnerID string) (DurableRunSnapshot, string, error)
}
WorkTaskClaimPort claims the referenced automation run for execution on behalf of runnerID and returns the post-claim run snapshot plus the opaque claim token. Test adapters implement it over the current service's ClaimNextRun; they must fail when the claimed run is not the referenced run, and must return metadata only.
type WorkTaskObserver ¶
type WorkTaskObserver interface {
LoadTaskStatus(ctx context.Context, ref SafeWorkTaskRef) (SafeTaskSnapshot, error)
}
WorkTaskObserver loads a metadata-only snapshot of a work task. Implementations live beside the projectworkplan service; they must return only ids, refs, and statuses.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package activities hosts the durable activities for the go-workflows pilot: the observe-only shadow activities (Phase 3) and the test-only execution activities (Phase 4).
|
Package activities hosts the durable activities for the go-workflows pilot: the observe-only shadow activities (Phase 3) and the test-only execution activities (Phase 4). |
|
Package workflows hosts the deterministic go-workflows workflow code for the durable shadow pilot (Phase 3).
|
Package workflows hosts the deterministic go-workflows workflow code for the durable shadow pilot (Phase 3). |