projectdurable

package
v0.3.3 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: MIT Imports: 14 Imported by: 0

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

View Source
const (
	ActivityStatusOK      = "ok"
	ActivityStatusBlocked = "blocked"
	ActivityStatusFailed  = "failed"
	ActivityStatusSkipped = "skipped"
)

Activity result statuses recorded by durable activities.

View Source
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

View Source
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.

View Source
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

func ValidateSafeRef(ref string) error

ValidateSafeRef applies small local checks to a single ref: non-empty, at most 200 chars, no control characters or whitespace.

func ValidateSafeSummary

func ValidateSafeSummary(s string) error

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 mirrors projectautomation.RunStatusRunnerUnavailable.
	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 mirrors safeCodexFailureCategory.
	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

func NewSQLiteEngine(sqlitePath string) (*Engine, error)

NewSQLiteEngine returns an Engine backed by a safe repo-local SQLite file. It does not start workers; callers must explicitly start the orchestrator.

func (*Engine) Close

func (e *Engine) Close() error

Close releases the backend. The engine is unusable afterwards.

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 (*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).

Jump to

Keyboard shortcuts

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