workflow

package
v0.50.97 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package workflow holds the shared schema contract for the harness workflow route. The manifest (route_a.schema.json) is the machine-authoritative source for phase-id, retry, budget, and result-type sets; this package parses it.

This package MUST NOT import pkg/content or internal/cli.

Index

Constants

View Source
const (
	MaxVerifyVotes = 3
	MaxFanOut      = 5
	MaxRetry       = 3
	// MaxPhases bounds the declared phase count. The team workflow generator
	// labels segments with string(rune('A'+segmentIndex)); since segments never
	// exceed phases, capping phases at 26 keeps every segment label within the
	// safe A..Z charset — closing the one generated-JS token not otherwise behind
	// a charset whitelist (defense-in-depth at the SoT parse boundary).
	MaxPhases = 26
)

Depth caps. These are hard ceilings enforced at the parse boundary; values above them are REJECTED (fail-closed), never silently clamped.

View Source
const (
	// RouteA is the model-agnostic deterministic workflow route.
	RouteA = "route_a"
	// RouteTeam is the deterministic team route whose planning phase pins Opus 5.
	RouteTeam = "route_team"

	// RouteAMinVersion preserves the original Dynamic Workflows compatibility
	// floor for the model-agnostic Route A.
	RouteAMinVersion = "2.1.154"
	// RouteTeamMinVersion is the first Claude Code release that recognizes the
	// fixed claude-opus-5 model used by Route Team.
	RouteTeamMinVersion = "2.1.219"

	// MinVersion is kept as the Route A compatibility floor for callers that use
	// the original route-agnostic EvaluateCapabilities API.
	MinVersion = RouteAMinVersion
)
View Source
const (
	// StatusAvailable / StatusUnavailable are the per-primitive probe states.
	StatusAvailable   = "available"
	StatusUnavailable = "unavailable"
	// OverallPass / OverallFail are the capability gate verdicts.
	OverallPass = "pass"
	OverallFail = "fail"
)
View Source
const DefaultSourceLimit = 300

DefaultSourceLimit is the hard per-file source line limit.

View Source
const VerdictSourceExitCode = "exit_code"

VerdictSourceExitCode is the canonical verdict source for the deterministic gate: the verdict derives from build/test command exit codes, never from an LLM verdict.

Variables

View Source
var AdvisoryPrimitives = []string{"budget", "agent-model-override"}

AdvisoryPrimitives are probed and reported but never affect the verdict.

View Source
var GeneratedSurfaceExactPaths = []string{
	".agents/plugins/marketplace.json",
	".autopus/context/signatures.md",
	"config.toml",
}

GeneratedSurfaceExactPaths are generated/runtime files that are not cleanly expressible as directory prefixes without blocking human-managed project docs.

View Source
var GeneratedSurfacePrefixes = []string{
	".claude/",
	".codex/",
	".gemini/",
	".opencode/",
	".agents/plugins/",
	".autopus/brainstorms/",
	".autopus/orchestra/",
	".autopus/plugins/",
	".autopus/txns/",
}

GeneratedSurfacePrefixes are the path prefixes the release hygiene drift gate treats as generated surfaces. Staging any of these without a corresponding source-of-truth change is blocked (REQ-012). The .autopus entries are scoped so legitimate `.autopus/specs` and `.autopus/project` edits are not blocked.

View Source
var RequiredPrimitives = []string{"claude", "agent", "schema", "phase", "parallel", "isolation"}

RequiredPrimitives are hard-gated: any unavailable one fails the gate.

parallel and isolation are required (not advisory) because the generated route_team workflow JS hard-depends on them: the implementation phase dispatches its executor fan-out through parallel(...) with each executor carrying isolation: 'worktree' (SPEC-HARNESS-WORKFLOW-FIDELITY-001 REQ-004). A runtime missing either primitive would pass an advisory-only gate and then crash mid-launch at the parallel(...) call — strictly worse than failing the gate up front and falling back to the safe Route A path. Gating them makes that failure fail-fast at the doctor boundary.

Functions

func CheckPendingLore

func CheckPendingLore(msg string, cfg lore.LoreConfig) []string

CheckPendingLore validates the pending commit message against the Lore format and returns human-readable violation messages (empty when the message is valid). It reuses the canonical lore.Validate.

func CheckStagedSourceSizes

func CheckStagedSourceSizes(fileLineCounts map[string]int, limit int) []string

CheckStagedSourceSizes returns the paths whose line count exceeds limit.

func DetectGeneratedDrift

func DetectGeneratedDrift(stagedPaths []string, sotChanged bool) []string

DetectGeneratedDrift returns the staged paths that live under a generated surface prefix when no source-of-truth change accompanies them. When sotChanged is true the generated regeneration is legitimate and nothing is blocked.

func MinimumVersionForRoute added in v0.50.88

func MinimumVersionForRoute(route string) (string, error)

MinimumVersionForRoute returns the Claude Code compatibility floor for a canonical workflow route and fails closed for unknown routes.

func ParseCoverage added in v0.50.59

func ParseCoverage(stdout string) (float64, bool)

ParseCoverage extracts the coverage percentage from stdout.

func PromptManifestHash

func PromptManifestHash(layers []promptlayer.Layer) string

PromptManifestHash folds the sorted per-layer content hashes of the non-ephemeral (stable + snapshot) layers into one sha256 hex digest. Ephemeral layers are excluded, so mutating only ephemeral context leaves the hash unchanged while mutating any stable/snapshot layer changes it.

Types

type CapabilityReport

type CapabilityReport struct {
	Route          string            `json:"route"`
	MinimumVersion string            `json:"minimum_version"`
	Primitives     []PrimitiveStatus `json:"primitives"`
	Version        string            `json:"version"`
	VersionOK      bool              `json:"version_ok"`
	Overall        string            `json:"overall"`
}

CapabilityReport is the structured `auto workflow doctor` output.

func EvaluateCapabilities

func EvaluateCapabilities(p Prober) CapabilityReport

EvaluateCapabilities probes required and advisory primitives plus the version pin for the original Route A contract. Call EvaluateCapabilitiesForRoute when the selected route is known.

Named EvaluateCapabilities (not Evaluate) because the gate evaluator EvaluateGate shares this package; Go forbids two same-named funcs.

func EvaluateCapabilitiesForRoute added in v0.50.88

func EvaluateCapabilitiesForRoute(p Prober, route string) (CapabilityReport, error)

EvaluateCapabilitiesForRoute probes required and advisory primitives plus the selected route's version pin. Overall is "fail" iff any required primitive is unavailable OR the version is below that route's minimum. Advisory primitives are reported with Gating=false and never change Overall.

func (CapabilityReport) EncodeJSON

func (r CapabilityReport) EncodeJSON() ([]byte, error)

EncodeJSON serializes the capability report for CLI stdout consumption.

type CommandRunner

type CommandRunner interface {
	// Run executes name with args and returns the process exit code. err is
	// non-nil when the command could not be started or exited non-zero; the
	// exit code remains authoritative for the verdict.
	Run(ctx context.Context, name string, args ...string) (exitCode int, err error)
}

CommandRunner is the injectable seam the deterministic gate uses to run the build and test commands. The production implementation wraps exec; tests inject a fake returning fixed exit codes. This keeps the gate independent of pkg/pipeline.PhaseBackend for exit-code data (REQ-011).

type ConsolidatedVerdict added in v0.50.59

type ConsolidatedVerdict struct {
	Barrier bool
	Reason  string
}

ConsolidatedVerdict holds the consolidated review status.

func ConsolidateReviewVerdict added in v0.50.59

func ConsolidateReviewVerdict(reviewerApprove, securityFail bool) ConsolidatedVerdict

ConsolidateReviewVerdict combines reviewer and security-auditor votes. Security FAIL always outranks code-quality reviewer APPROVE.

type CoverageRunner added in v0.50.59

type CoverageRunner interface {
	RunOutput(ctx context.Context, name string, args ...string) (stdout string, exitCode int, err error)
}

CoverageRunner is distinct from the exit-code-only CommandRunner. It returns stdout in addition to the exit code and error.

type DepthProfile added in v0.50.57

type DepthProfile struct {
	VerifyVotes int
	FanOutCap   int
	Synthesis   bool
	Retry       int
}

DepthProfile is the bounded per-phase execution depth derived from a quality tier. It governs how many verify votes and fan-out branches a phase may use, whether a synthesis pass runs, and the retry budget. All values are capped (REQ-004, S4) so a quality tier can never request unbounded depth.

func ResolveDepth added in v0.50.57

func ResolveDepth(quality string) DepthProfile

ResolveDepth maps a quality tier to a bounded DepthProfile. "ultra" runs the deepest allowed profile (max verify votes, full fan-out, synthesis on); "balanced" and any other/unknown value fall back to the conservative default.

type DryRunReport

type DryRunReport struct {
	PhaseOrder         []string        `json:"phase_order"`
	GateVerdictSource  string          `json:"gate_verdict_source"`
	ManifestPath       string          `json:"manifest_path"`
	SchemaPath         string          `json:"schema_path"`
	PromptManifestHash string          `json:"prompt_manifest_hash"`
	JS                 string          `json:"js"`
	Phases             []RenderedPhase `json:"phases"`
}

DryRunReport is the inspectable output of `auto workflow render --dry-run`: the deterministic phase order, the gate verdict source, the manifest/schema paths, a deterministic prompt-manifest hash, and the generated workflow JS.

func Render

func Render(s Schema, layers []promptlayer.Layer, jsContent, manifestPath, schemaPath string) DryRunReport

Render builds the dry-run report from the parsed schema, prompt layers, and generated JS. PhaseOrder comes from the manifest; GateVerdictSource is the canonical "exit_code"; the prompt-manifest hash is deterministic over the non-ephemeral layers. Render is pure: it reads no files, the CLI passes data.

type FailureKind

type FailureKind string

FailureKind enumerates the workflow route failure causes the classifier recognizes.

const (
	FailureNonClaudePlatform FailureKind = "non_claude_platform"
	FailureDoctorFail        FailureKind = "doctor_fail"
	FailureParityDrift       FailureKind = "parity_drift"
	FailureExecutionAbort    FailureKind = "execution_abort"
	FailureAPIUnavailable    FailureKind = "api_unavailable"
)

func KnownFailureKinds

func KnownFailureKinds() []FailureKind

KnownFailureKinds returns the failure kinds the classifier recognizes.

type FallbackClass

type FallbackClass string

FallbackClass is the taxonomy bucket a workflow route failure is classified into. Every known failure maps to exactly one class; silent opt-out is forbidden (REQ-008).

const (
	// FallbackFailFast: abort the workflow immediately and fall back to Route A.
	FallbackFailFast FallbackClass = "fail-fast"
	// FallbackFailClosed: refuse to proceed and block (e.g. parity drift).
	FallbackFailClosed FallbackClass = "fail-closed"
	// FallbackResumable: the run can be resumed from a recorded checkpoint.
	FallbackResumable FallbackClass = "resumable"
	// FallbackExplicit: surface to the operator for an explicit decision.
	FallbackExplicit FallbackClass = "explicit"
)

func Classify

func Classify(k FailureKind) (FallbackClass, bool)

Classify returns the fallback class for a failure kind. ok is false for an unknown kind so callers can detect (and never silently swallow) an unclassified failure.

type GateRemediationDecision added in v0.50.59

type GateRemediationDecision struct {
	FixerAttempts    int
	SegmentBLaunched bool
	Aborted          bool
	AbortReason      string
}

GateRemediationDecision holds the verdict computed by RunGateRemediation.

func RunGateRemediation added in v0.50.59

func RunGateRemediation(budget int, evals []GateSignature) GateRemediationDecision

RunGateRemediation computes the bounded remediation decision for the gate.

type GateResult

type GateResult struct {
	Verdict       string `json:"verdict"`
	VerdictSource string `json:"verdict_source"`
	BuildExit     int    `json:"build_exit"`
	TestExit      int    `json:"test_exit"`
}

GateResult is the structured verdict the `auto workflow gate` CLI emits for the workflow JS to read and branch on.

func EvaluateCoverageGate added in v0.50.59

func EvaluateCoverageGate(ctx context.Context, runner CoverageRunner, coverageCmd []string, threshold int) GateResult

EvaluateCoverageGate parses the measured coverage percentage from stdout, compares it to the threshold, and returns a GateResult.

func EvaluateGate

func EvaluateGate(ctx context.Context, runner CommandRunner, buildCmd, testCmd []string) GateResult

EvaluateGate runs the build and test commands through the runner seam and derives a deterministic verdict from their exit codes. VerdictSource is always "exit_code"; Verdict is "pass" iff both exit codes are 0, else "fail".

Named EvaluateGate (not Evaluate) because the doctor capability evaluator EvaluateCapabilities shares this package; Go forbids two same-named funcs.

func (GateResult) EncodeJSON

func (r GateResult) EncodeJSON() ([]byte, error)

EncodeJSON serializes the gate result for CLI stdout consumption.

type GateSignature added in v0.50.59

type GateSignature struct {
	BuildExit int
	TestExit  int
}

GateSignature represents the exit codes of a build/test run.

type GitOutputRunner added in v0.50.57

type GitOutputRunner interface {
	// Run executes a git subcommand in dir and returns (stdout, exitCode, err).
	// err is non-nil when the process could not be started; exitCode is
	// authoritative for failure detection.
	Run(ctx context.Context, dir string, args ...string) (stdout string, exitCode int, err error)
}

GitOutputRunner runs a git subcommand in dir and captures stdout. The production implementation wraps os/exec; tests inject a fake. This interface is separate from CommandRunner because merge needs stdout text (parsed worktree list, changed-file list), not just an exit code.

type HygieneReport

type HygieneReport struct {
	Blocked      bool     `json:"blocked"`
	BlockedPaths []string `json:"blocked_paths"`
	Reasons      []string `json:"reasons"`
}

HygieneReport is the aggregated release hygiene verdict. Blocked is true when any generated-surface drift, oversized source file, or Lore violation exists.

func Hygiene

func Hygiene(staged []string, sotChanged bool, sizes map[string]int, limit int, msg string, cfg lore.LoreConfig) HygieneReport

Hygiene aggregates the drift, source-size, and Lore checks into one report. staged/sotChanged feed the generated-surface drift gate; sizes/limit feed the 300-line source limit; msg/cfg feed the pending-message Lore check. The function is pure and injectable — no live git access — so it stays hermetic.

type PhaseBinding added in v0.50.57

type PhaseBinding struct {
	Model       string `json:"model"`
	Effort      string `json:"effort"`
	VerifyVotes int    `json:"verify_votes"`
	FanOutCap   int    `json:"fan_out_cap"`
	Synthesis   bool   `json:"synthesis"`
}

PhaseBinding is the complete per-phase quality binding the dispatch layer computes for a single phase. All fields are kept (no omitempty) so the serialized JSON is deterministic regardless of zero values.

type PhaseDef

type PhaseDef struct {
	ID                string `json:"id"`
	Retry             int    `json:"retry"`
	Budget            int    `json:"budget"`
	ResultType        string `json:"result_type"`
	Model             string `json:"model"`
	Effort            string `json:"effort"`
	VerifyVotes       int    `json:"verify_votes"`
	FanOutCap         int    `json:"fan_out_cap"`
	Synthesis         bool   `json:"synthesis"`
	CoverageThreshold int    `json:"coverage_threshold"`
}

PhaseDef is a single workflow phase as declared in route_a.schema.json. ResultType carries the verdict_source for the deterministic gate phase (e.g. "exit_code"); it is "" for non-gate phases.

type PrimitiveStatus

type PrimitiveStatus struct {
	Name   string `json:"name"`
	Status string `json:"status"`
	Gating bool   `json:"gating"`
}

PrimitiveStatus is a single probed primitive in the capability report. Gating is true for required primitives, false for advisory ones.

type Prober

type Prober interface {
	// Probe reports whether a named workflow primitive is available.
	Probe(primitive string) bool
	// Version returns the probed claude-code version string (dotted ints).
	Version() string
}

Prober is the injectable capability-probe seam. The production implementation inspects the claude-code runtime; tests inject a fake.

type QualityBinding added in v0.50.57

type QualityBinding struct {
	Phases map[string]PhaseBinding `json:"phases"`
}

QualityBinding maps phase-id to its computed PhaseBinding.

type RenderedPhase added in v0.50.57

type RenderedPhase struct {
	ID          string `json:"id"`
	Model       string `json:"model"`
	Effort      string `json:"effort"`
	VerifyVotes int    `json:"verify_votes"`
	FanOutCap   int    `json:"fan_out_cap"`
	Synthesis   bool   `json:"synthesis"`
}

RenderedPhase exposes the per-phase model, effort, and depth surface so the dry-run report is inspectable (REQ-012, S9). It is the rendered (baseline or overlaid) view of a single phase.

func OverlayPhases added in v0.50.57

func OverlayPhases(s Schema, b *QualityBinding) []RenderedPhase

OverlayPhases builds the rendered per-phase view in schema order. Each phase starts from its schema baseline (the PhaseDef values). When b is non-nil and carries an entry for a phase id, that phase's quality fields are replaced wholesale with the binding's values — the dispatch computes the complete per-phase binding, so this is a replace, not a merge. Phases without a binding entry keep their baseline (deterministic gate phases stay empty).

type ReviewBarrierDecision added in v0.50.59

type ReviewBarrierDecision struct {
	FixerAttempts         int
	Aborted               bool
	AbortReason           string
	ReleaseHygieneReached bool
}

ReviewBarrierDecision holds the outcome of the review barrier loop.

func RunReviewBarrier added in v0.50.59

func RunReviewBarrier(budget int, rounds []ConsolidatedVerdict) ReviewBarrierDecision

RunReviewBarrier computes the bounded review barrier outcome.

type Schema

type Schema struct {
	Phases []PhaseDef `json:"phases"`
}

Schema is the parsed manifest with phases in execution order.

func LoadSchema

func LoadSchema(path string) (Schema, error)

LoadSchema reads and parses route_a.schema.json from path.

func ParseSchema

func ParseSchema(data []byte) (Schema, error)

ParseSchema unmarshals route_a.schema.json bytes into a Schema, preserving phase array order as execution order. @AX:WARN [AUTO]: 11 fail-closed validation branches guard the JS-injection trust boundary (phase count/id/model/effort/result_type/depth caps). @AX:REASON [AUTO]: This is the single SoT parse gate for generated workflow JS; any branch weakened or reordered can let an unsafe field reach the generated-JS surface. Treat additions as security-relevant.

func (Schema) BudgetSet

func (s Schema) BudgetSet() map[string]int

BudgetSet returns budgets keyed by phase-id.

func (Schema) DepthSet added in v0.50.57

func (s Schema) DepthSet() map[string]DepthProfile

DepthSet returns the bounded DepthProfile for each phase keyed by phase-id.

func (Schema) EffortSet added in v0.50.57

func (s Schema) EffortSet() map[string]string

EffortSet returns effort tiers keyed by phase-id.

func (Schema) ModelSet added in v0.50.57

func (s Schema) ModelSet() map[string]string

ModelSet returns agent model identifiers keyed by phase-id.

func (Schema) PhaseIDs

func (s Schema) PhaseIDs() []string

PhaseIDs returns the ordered phase-ids.

func (Schema) ResultTypeSet

func (s Schema) ResultTypeSet() map[string]string

ResultTypeSet returns result-types keyed by phase-id.

func (Schema) RetrySet

func (s Schema) RetrySet() map[string]int

RetrySet returns retry counts keyed by phase-id.

type TaskOwnership added in v0.50.58

type TaskOwnership struct {
	ID    string   `json:"id"`
	Files []string `json:"files"`
}

TaskOwnership is one planner task's file ownership. It is used to ENFORCE that an executor's merged changes stay within its assigned files, turning the planner's disjoint-file decomposition into a hard merge-time guarantee.

func ParsePlanOwnership added in v0.50.58

func ParsePlanOwnership(data []byte) ([]TaskOwnership, error)

ParsePlanOwnership extracts task file-ownership from a persisted planner result. It accepts either {"tasks":[...]} or {"plan":{"tasks":[...]}} — the dispatcher persists the segment-A return value, which wraps the plan under "plan".

type WorktreeMergeResult added in v0.50.57

type WorktreeMergeResult struct {
	RunID           string   `json:"run_id"`
	MergedWorktrees []string `json:"merged_worktrees"`
	MergedFiles     []string `json:"merged_files"`
	Conflicts       []string `json:"conflicts"`
	// SkippedOutOfScope lists files an executor created outside its task's file
	// ownership (only populated when ownership enforcement is active). They are
	// reported but never copied.
	SkippedOutOfScope []string `json:"skipped_out_of_scope,omitempty"`
}

WorktreeMergeResult is the structured output emitted by MergeExecutorWorktrees and printed as JSON by `auto workflow merge`.

func MergeExecutorWorktrees added in v0.50.57

func MergeExecutorWorktrees(ctx context.Context, r GitOutputRunner, workingDir, runID string) (WorktreeMergeResult, error)

MergeExecutorWorktrees consolidates uncommitted changes from all executor worktrees belonging to runID into workingDir.

The Claude Code Workflow runtime creates one worktree per parallel executor. Worktree branch naming is an observed runtime convention (v2.1.174+):

  • worktree path base: <runID>-<N> (under .claude/worktrees/)
  • branch: worktree-<runID>-<N>

Executor changes are left as uncommitted working-tree edits (git status shows ?? / M / A). This function copies those files into workingDir so that `auto workflow gate` sees them. It does NOT git-add, commit, or remove worktrees — the CLI layer handles those steps.

Conflict policy: if more than one worktree touches the same repo-relative path, the path is added to Conflicts and skipped (not copied). Planner file-ownership makes this rare; the CLI/operator decides how to resolve.

func MergeExecutorWorktreesWithOwnership added in v0.50.58

func MergeExecutorWorktreesWithOwnership(ctx context.Context, r GitOutputRunner, workingDir, runID string, ownership []TaskOwnership) (WorktreeMergeResult, error)

MergeExecutorWorktreesWithOwnership is MergeExecutorWorktrees with hard file ownership enforcement. When ownership is non-nil, each worktree is matched to the task it performed (best file overlap) and only files within that task's ownership are merged; files an executor created outside its ownership (overlap into another task's files) are reported in SkippedOutOfScope and never copied. This eliminates the executor-overlap conflict at its source. ownership=nil preserves the plain conflict-skip behavior.

func (WorktreeMergeResult) EncodeJSON added in v0.50.57

func (r WorktreeMergeResult) EncodeJSON() ([]byte, error)

EncodeJSON serializes the merge result for CLI stdout consumption.

Jump to

Keyboard shortcuts

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