effects

package
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package effects defines Pasture's typed process, Git, and filesystem workflow effect algebra: opaque, constructor-validated operands and closed effect sums that make operational semantics explicit instead of hiding them in shell-fragment strings.

The package models effects; it does not grant permission. Typing an effect never bypasses harness, user-sandbox, escalation, or hook policy — execution of any effect still obeys those constraints. See RuntimeClass for how each effect is classified for a runtime contract.

Import direction is strictly one-way: a consumer such as the authoritative task package imports effects and immediately hands a verified proof (see VerifiedGuardedPush) to its protected commit. effects never imports the task package; TestEffectsImportsNoTaskPackage enforces that edge.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultCommandRunner

func DefaultCommandRunner(dir, executable string, args ...string) (string, error)

DefaultCommandRunner runs git through os/exec, returning trimmed combined output or an actionable error.

Types

type Argument

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

Argument is one literal argv element. It is passed verbatim to the program with execve semantics — never re-parsed by a shell — so it may legitimately contain spaces, quotes, or characters that would be special to a shell. Only NUL and invalid UTF-8, which cannot cross a process boundary, are rejected.

func NewArgument

func NewArgument(value string) (Argument, error)

NewArgument validates one literal argv element.

func (Argument) IsValid

func (a Argument) IsValid() bool

func (Argument) String

func (a Argument) String() string

type CaptureID

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

CaptureID names one captured process output stream so a later pipeline step can consume it as previous-output input. It is a pipeline-local identity, not a portable namespaced identity.

func NewCaptureID

func NewCaptureID(value string) (CaptureID, error)

NewCaptureID validates a pipeline-local capture identity.

func (CaptureID) IsValid

func (c CaptureID) IsValid() bool

func (CaptureID) String

func (c CaptureID) String() string

type CommandRunner

type CommandRunner func(dir, executable string, args ...string) (string, error)

CommandRunner runs a resolved command in a working directory and returns its combined output. It is injected so git effects can be driven without touching a real repository in tests.

type CommitOID

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

CommitOID is a full, lowercase-hex git commit object id.

func NewCommitOID

func NewCommitOID(value string) (CommitOID, error)

NewCommitOID validates a full commit object id.

func (CommitOID) Equal

func (c CommitOID) Equal(other CommitOID) bool

func (CommitOID) IsValid

func (c CommitOID) IsValid() bool

func (CommitOID) String

func (c CommitOID) String() string

type CommitPolicy

type CommitPolicy string

CommitPolicy is the closed set of repository commit policies. A policy is an explicit operand and contract, not a best-effort renderer substitution: a repository that requires `git agent-commit` names it here, and a lowerer may not silently substitute a plain `git commit`.

const (
	// CommitPolicyAgentCommit requires the repository's `git agent-commit`.
	CommitPolicyAgentCommit CommitPolicy = "git-agent-commit"
	// CommitPolicyPlainCommit uses a plain `git commit` where the repository
	// permits it.
	CommitPolicyPlainCommit CommitPolicy = "git-commit"
)

func (CommitPolicy) IsValid

func (p CommitPolicy) IsValid() bool

type Effect

type Effect interface {
	// Classify reports the runtime class a contract must honor for this effect.
	Classify() RuntimeClass
	// contains filtered or unexported methods
}

Effect is the closed super-sum of every modeled workflow effect. Each variant is an opaque constructor-owned value; the marker method keeps the sum closed so exhaustive lowering and classification cannot silently miss a variant.

type EnvBinding

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

EnvBinding is one typed environment variable binding. The value is a literal string, never shell-expanded: a value of "$HOME" is the five literal characters, not the caller's home directory.

func NewEnvBinding

func NewEnvBinding(name, value string) (EnvBinding, error)

NewEnvBinding validates an environment variable name and literal value.

func (EnvBinding) IsValid

func (b EnvBinding) IsValid() bool

func (EnvBinding) Name

func (b EnvBinding) Name() string

func (EnvBinding) Value

func (b EnvBinding) Value() string

type ExecutableRef

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

ExecutableRef names the program to run. It is opaque and constructor-owned: the executable is resolved at execution time through an injected lookup (see ExecutableResolver), never interpreted by a shell. A ref may carry a path separator (for an absolute or relative program path) but never a shell metacharacter.

func NewExecutableRef

func NewExecutableRef(name string) (ExecutableRef, error)

NewExecutableRef validates a program name or path for execve-style dispatch.

func (ExecutableRef) IsValid

func (e ExecutableRef) IsValid() bool

func (ExecutableRef) String

func (e ExecutableRef) String() string

type ExecutableResolver

type ExecutableResolver func(name string) (string, error)

ExecutableResolver resolves a program name to an executable path, exactly like exec.LookPath. It is injected so process and git effects never assume a fixed binary location and can be exercised against a stub in tests.

type ExitExpectation

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

ExitExpectation is the immutable sorted, deduplicated set of process exit codes accepted as success. Its zero value is invalid: an effect must state exactly which exits it treats as success.

func ExpectSuccess

func ExpectSuccess() ExitExpectation

ExpectSuccess is the common expectation that only exit code 0 is success.

func NewExitExpectation

func NewExitExpectation(codes ...int) (ExitExpectation, error)

NewExitExpectation builds an expected-exit set from one or more codes.

func (ExitExpectation) Accepts

func (e ExitExpectation) Accepts(code int) bool

Accepts reports whether code is in the success set.

func (ExitExpectation) Codes

func (e ExitExpectation) Codes() []int

Codes returns a defensive copy of the accepted exit codes in ascending order.

func (ExitExpectation) IsValid

func (e ExitExpectation) IsValid() bool

type ExpectedOldOID

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

ExpectedOldOID states what the remote ref must currently be for a guarded push to proceed: either explicitly absent (the ref must not exist) or an exact prior commit. Its zero value is invalid — a guarded push must state its expectation explicitly, never leave it unspecified.

func ExpectAbsentRemote

func ExpectAbsentRemote() ExpectedOldOID

ExpectAbsentRemote states the remote ref must not currently exist.

func ExpectRemoteAt

func ExpectRemoteAt(oid CommitOID) (ExpectedOldOID, error)

ExpectRemoteAt states the remote ref must currently be exactly oid.

func (ExpectedOldOID) Absent

func (e ExpectedOldOID) Absent() bool

Absent reports whether the expectation is that the remote ref does not exist.

func (ExpectedOldOID) Commit

func (e ExpectedOldOID) Commit() (CommitOID, bool)

Commit returns the expected prior commit and true when the expectation is a specific commit rather than absence.

func (ExpectedOldOID) IsValid

func (e ExpectedOldOID) IsValid() bool

type FileSystemEffect

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

FileSystemEffect is the closed sum of modeled filesystem effects. Every variant names exact owned paths; none can name a glob, so a removal can never expand to an unowned set of files. It is an Effect variant, classified native.

func NewCreateDirectory

func NewCreateDirectory(target OwnedPath) (FileSystemEffect, error)

NewCreateDirectory creates one owned directory path.

func NewMoveFile

func NewMoveFile(from, to OwnedPath) (FileSystemEffect, error)

NewMoveFile moves one owned path to another owned path.

func NewReadFile

func NewReadFile(target OwnedPath) (FileSystemEffect, error)

NewReadFile reads the exact content of one owned path.

func NewRemoveFile

func NewRemoveFile(target OwnedPath) (FileSystemEffect, error)

NewRemoveFile removes exactly one owned path. It cannot name a glob, so it can never expand to an unowned set of files.

func NewWriteReplaceFile

func NewWriteReplaceFile(target OwnedPath, content []byte) (FileSystemEffect, error)

NewWriteReplaceFile writes exact content to one owned path.

func (FileSystemEffect) Classify

func (f FileSystemEffect) Classify() RuntimeClass

Classify reports the runtime class. Filesystem effects are executed directly by the host runtime.

func (FileSystemEffect) Content

func (f FileSystemEffect) Content() ([]byte, bool)

Content returns a defensive copy of the write content and true for a write-replace effect.

func (FileSystemEffect) Destination

func (f FileSystemEffect) Destination() (OwnedPath, bool)

Destination returns the move destination and true for a move effect.

func (FileSystemEffect) IsValid

func (f FileSystemEffect) IsValid() bool

func (FileSystemEffect) Kind

func (FileSystemEffect) Path

func (f FileSystemEffect) Path() OwnedPath

func (FileSystemEffect) StateChanging

func (f FileSystemEffect) StateChanging() bool

StateChanging reports whether the effect mutates the filesystem. Only FSRead is read-only.

type FileSystemEffectKind

type FileSystemEffectKind string

FileSystemEffectKind is the closed set of modeled filesystem effects.

const (
	// FSRead reads the exact content of one owned path.
	FSRead FileSystemEffectKind = "read"
	// FSWriteReplace writes exact content to one owned path, replacing any
	// prior content.
	FSWriteReplace FileSystemEffectKind = "write-replace"
	// FSCreateDirectory creates one owned directory path.
	FSCreateDirectory FileSystemEffectKind = "create-directory"
	// FSMove moves one owned path to another owned path.
	FSMove FileSystemEffectKind = "move"
	// FSRemove removes exactly one owned path.
	FSRemove FileSystemEffectKind = "remove"
)

type GitEffect

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

GitEffect is the closed sum of modeled non-landing git effects. It is opaque and constructor-owned. Read evidence effects report StateChanging() == false; stage/commit/fetch/rebase report true. It is an Effect variant.

func NewGitCommit

func NewGitCommit(repository RepositoryID, policy CommitPolicy) (GitEffect, error)

NewGitCommit builds a commit effect bound to an explicit repository commit policy. The policy is an operand, never inferred by a renderer.

func NewGitFetch

func NewGitFetch(repository RepositoryID, remote RemoteRef) (GitEffect, error)

NewGitFetch builds a fetch effect from a remote ref.

func NewGitReadEvidence

func NewGitReadEvidence(repository RepositoryID, kind GitEffectKind) (GitEffect, error)

NewGitReadEvidence builds a read-only git evidence effect (status, commit, or diff evidence).

func NewGitRebase

func NewGitRebase(repository RepositoryID, onto RemoteRef) (GitEffect, error)

NewGitRebase builds a rebase effect onto a remote ref.

func NewGitStage

func NewGitStage(repository RepositoryID, paths ...OwnedPath) (GitEffect, error)

NewGitStage stages exact owned paths in a repository.

func (GitEffect) Classify

func (g GitEffect) Classify() RuntimeClass

Classify reports the runtime class. A commit under repository policy is a semantic instruction the agent carries out; every other modeled git effect is executed natively.

func (GitEffect) IsValid

func (g GitEffect) IsValid() bool

func (GitEffect) Kind

func (g GitEffect) Kind() GitEffectKind

func (GitEffect) Paths

func (g GitEffect) Paths() ([]OwnedPath, bool)

Paths returns the staged paths and true for a stage effect.

func (GitEffect) Policy

func (g GitEffect) Policy() (CommitPolicy, bool)

Policy returns the commit policy and true for a commit effect.

func (GitEffect) Remote

func (g GitEffect) Remote() (RemoteRef, bool)

Remote returns the remote ref and true for a fetch or rebase effect.

func (GitEffect) Repository

func (g GitEffect) Repository() RepositoryID

func (GitEffect) StateChanging

func (g GitEffect) StateChanging() bool

StateChanging reports whether the effect mutates repository or remote state. The three evidence kinds are read-only.

type GitEffectKind

type GitEffectKind string

GitEffectKind is the closed set of modeled non-landing git effects. The only landing push effect is the guarded push (see GuardedPushInput), which is a distinct parent-mediated effect.

const (
	// GitStatusEvidence reads repository status as read-only evidence.
	GitStatusEvidence GitEffectKind = "status-evidence"
	// GitCommitEvidence attaches an exact commit as read-only evidence.
	GitCommitEvidence GitEffectKind = "commit-evidence"
	// GitDiffEvidence attaches an exact diff as read-only evidence.
	GitDiffEvidence GitEffectKind = "diff-evidence"
	// GitStage stages exact owned paths.
	GitStage GitEffectKind = "stage"
	// GitCommit creates a commit under an explicit repository commit policy.
	GitCommit GitEffectKind = "commit"
	// GitFetch fetches from a remote where the protocol has authority.
	GitFetch GitEffectKind = "fetch"
	// GitRebase rebases where the protocol has authority.
	GitRebase GitEffectKind = "rebase"
)

type GitRepositoryPusher

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

GitRepositoryPusher is the production RepositoryPusher backed by a git executable. It carries no guarded-push policy — verify/push/re-read primitives only; the verify-push-reread-then-prove algorithm lives in GuardedPushExactCommit. RepositoryID names the repository working directory, and remoteName is the configured git remote the RemoteRef is pushed to.

func NewGitRepositoryPusher

func NewGitRepositoryPusher(resolve ExecutableResolver, run CommandRunner, remoteName string) (GitRepositoryPusher, error)

NewGitRepositoryPusher wires a git-backed pusher. resolve locates the git binary (pass exec.LookPath in production); run executes it (pass DefaultCommandRunner in production). remoteName is the git remote the guarded push targets (for example "origin").

func (GitRepositoryPusher) PushExact

func (p GitRepositoryPusher) PushExact(repository RepositoryID, commit CommitOID, remoteRef RemoteRef, expectedOld ExpectedOldOID) error

PushExact performs only the commit:remoteRef update under a force-with-lease guard derived from the expected-old state. An error is not by itself failure: GuardedPushExactCommit re-reads the remote to decide.

func (GitRepositoryPusher) ReadRemote

func (p GitRepositoryPusher) ReadRemote(repository RepositoryID, remoteRef RemoteRef) (RemoteState, error)

ReadRemote re-reads the current commit of remoteRef on the configured remote.

func (GitRepositoryPusher) VerifyLocalObject

func (p GitRepositoryPusher) VerifyLocalObject(repository RepositoryID, commit CommitOID, tree TreeDigest) error

VerifyLocalObject confirms the local repository holds the exact commit and that the commit's tree matches the expected tree digest.

type GuardedPushBatchResult

type GuardedPushBatchResult struct {
	Repository RepositoryID
	Proof      VerifiedGuardedPush
	Err        error
}

GuardedPushBatchResult is the per-repository result of a multi-repository guarded-push orchestration. Exactly one of Proof/Err is meaningful: a verified landing carries a Proof and nil Err; a failure carries a nil-proof Err. The batch makes no atomicity or rollback claim.

func GuardedPushBatch

func GuardedPushBatch(inputs []GuardedPushInput, pusher RepositoryPusher) []GuardedPushBatchResult

GuardedPushBatch orchestrates a guarded push per repository input in order. It records an exact per-repository result and, on the first failure, stops attempting further pushes — but it never rolls back an already-verified landing and never claims cross-repository atomicity. Results already produced are returned as-is; not-yet-attempted repositories are absent from the slice.

func (GuardedPushBatchResult) Verified

func (r GuardedPushBatchResult) Verified() bool

Verified reports whether this repository's landing produced a valid proof.

type GuardedPushInput

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

GuardedPushInput is the opaque, validated input to the one landing push effect. It names the repository, the exact local commit and the tree that commit must carry, the exact destination ref, and the expected prior state of that ref (including explicit absence). It is an Effect variant classified parent-mediated: only the parent orchestrator performs a landing push.

func NewGuardedPushInput

func NewGuardedPushInput(repository RepositoryID, commit CommitOID, tree TreeDigest, remoteRef RemoteRef, expectedOld ExpectedOldOID) (GuardedPushInput, error)

NewGuardedPushInput validates every operand of a guarded landing push.

func (GuardedPushInput) Classify

func (g GuardedPushInput) Classify() RuntimeClass

func (GuardedPushInput) Commit

func (g GuardedPushInput) Commit() CommitOID

func (GuardedPushInput) ExpectedOld

func (g GuardedPushInput) ExpectedOld() ExpectedOldOID

func (GuardedPushInput) IsValid

func (g GuardedPushInput) IsValid() bool

func (GuardedPushInput) RemoteRef

func (g GuardedPushInput) RemoteRef() RemoteRef

func (GuardedPushInput) Repository

func (g GuardedPushInput) Repository() RepositoryID

func (GuardedPushInput) Tree

func (g GuardedPushInput) Tree() TreeDigest

type GuardedPushOutcome

type GuardedPushOutcome string

GuardedPushOutcome is the closed set of successful guarded-push outcomes. Its zero value is invalid: a proof only ever carries one of these two verified outcomes.

const (
	// GuardedPushPushed means this call advanced the remote ref to the exact
	// commit and re-verified it.
	GuardedPushPushed GuardedPushOutcome = "pushed"
	// GuardedPushIdempotentReplay means the remote ref already held the exact
	// commit when this call ran, so the landing is a verified replay.
	GuardedPushIdempotentReplay GuardedPushOutcome = "idempotent-replay"
)

func (GuardedPushOutcome) IsValid

func (o GuardedPushOutcome) IsValid() bool

type InputKind

type InputKind string

InputKind is the closed set of process stdin sources.

const (
	// InputNone supplies no standard input.
	InputNone InputKind = "none"
	// InputLiteral supplies exact in-memory bytes.
	InputLiteral InputKind = "literal"
	// InputFile reads standard input from an owned file path.
	InputFile InputKind = "file"
	// InputPreviousOutput consumes a prior step's captured output, making
	// command substitution an explicit output-to-input dataflow edge.
	InputPreviousOutput InputKind = "previous-output"
)

type InputRef

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

InputRef is the closed sum of process standard-input sources.

func NewFileInput

func NewFileInput(path OwnedPath) (InputRef, error)

NewFileInput reads standard input from an owned file path.

func NewLiteralInput

func NewLiteralInput(content []byte) InputRef

NewLiteralInput supplies exact in-memory standard-input bytes.

func NewPreviousOutputInput

func NewPreviousOutputInput(capture CaptureID) (InputRef, error)

NewPreviousOutputInput consumes a prior step's captured output as this step's standard input. This is the only supported form of command substitution.

func NoInput

func NoInput() InputRef

NoInput supplies no standard input.

func (InputRef) File

func (i InputRef) File() (OwnedPath, bool)

File returns the input file path and true when the input reads from a file.

func (InputRef) IsValid

func (i InputRef) IsValid() bool

func (InputRef) Kind

func (i InputRef) Kind() InputKind

func (InputRef) Literal

func (i InputRef) Literal() ([]byte, bool)

Literal returns the literal input bytes and true when the input is literal.

func (InputRef) PreviousOutput

func (i InputRef) PreviousOutput() (CaptureID, bool)

PreviousOutput returns the referenced capture and true when the input is a previous-output dataflow edge.

type NodeType

type NodeType string

NodeType is the closed set of filesystem node types publication distinguishes.

const (
	// NodeAbsent means no node exists at the path.
	NodeAbsent NodeType = "absent"
	// NodeFile means a regular file exists at the path.
	NodeFile NodeType = "file"
	// NodeDir means a directory exists at the path.
	NodeDir NodeType = "dir"
	// NodeOther means an irregular node (symlink, device, ...) exists.
	NodeOther NodeType = "other"
)

type OSPublicationFS

type OSPublicationFS struct{}

OSPublicationFS is the production PublicationFS backed by the os package. It carries no reconciliation policy; that lives entirely in Publish. Paths are used verbatim, so callers pass a payload root that is already resolved to a real filesystem location.

func NewOSPublicationFS

func NewOSPublicationFS() OSPublicationFS

NewOSPublicationFS returns the os-backed publication filesystem seam.

func (OSPublicationFS) MkdirAll

func (OSPublicationFS) MkdirAll(target string, mode fs.FileMode) error

func (OSPublicationFS) ReadFile

func (OSPublicationFS) ReadFile(target string) ([]byte, error)

func (OSPublicationFS) Remove

func (OSPublicationFS) Remove(target string) error

func (OSPublicationFS) Stat

func (OSPublicationFS) Stat(target string) (PublishedNode, error)

Stat reports the node type and permission bits at target. A missing path is reported as NodeAbsent with a nil error. Symlinks and other irregular nodes are reported as NodeOther so publication treats them as unrelated drift rather than overwriting them.

func (OSPublicationFS) WriteFile

func (OSPublicationFS) WriteFile(target string, content []byte, mode fs.FileMode) error

type OutputKind

type OutputKind string

OutputKind is the closed set of process stdout/stderr sinks.

const (
	// OutputDiscard drops the stream.
	OutputDiscard OutputKind = "discard"
	// OutputCaptured captures the stream under a CaptureID for later dataflow.
	OutputCaptured OutputKind = "captured"
	// OutputFile writes the stream to an owned file path.
	OutputFile OutputKind = "file"
)

type OutputRef

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

OutputRef is the closed sum of process standard-output/standard-error sinks.

func DiscardOutput

func DiscardOutput() OutputRef

DiscardOutput drops the stream.

func NewCapturedOutput

func NewCapturedOutput(capture CaptureID) (OutputRef, error)

NewCapturedOutput captures the stream under capture for later dataflow.

func NewFileOutput

func NewFileOutput(path OwnedPath) (OutputRef, error)

NewFileOutput writes the stream to an owned file path.

func (OutputRef) Capture

func (o OutputRef) Capture() (CaptureID, bool)

Capture returns the capture id and true when the output is captured.

func (OutputRef) File

func (o OutputRef) File() (OwnedPath, bool)

File returns the output file path and true when the output writes to a file.

func (OutputRef) IsValid

func (o OutputRef) IsValid() bool

func (OutputRef) Kind

func (o OutputRef) Kind() OutputKind

type OwnedPath

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

OwnedPath is an exact, normalized, slash-separated relative path an effect is permitted to name. It is opaque and constructor-owned. It cannot be a glob, cannot escape its root with "..", and cannot be absolute — so a filesystem effect always names exactly one path it owns and can never expand to an unowned set of files.

func NewOwnedPath

func NewOwnedPath(raw string) (OwnedPath, error)

NewOwnedPath validates and normalizes an exact relative path.

func (OwnedPath) Equal

func (p OwnedPath) Equal(other OwnedPath) bool

Equal reports exact owned-path equality.

func (OwnedPath) IsValid

func (p OwnedPath) IsValid() bool

func (OwnedPath) String

func (p OwnedPath) String() string

type PathOutcome

type PathOutcome string

PathOutcome is the closed set of per-path reconciliation results.

const (
	// PathVerified means the on-disk state already matched the desired state.
	PathVerified PathOutcome = "verified"
	// PathCreated means a new desired file was written.
	PathCreated PathOutcome = "created"
	// PathUpdated means an existing managed file was rewritten to desired.
	PathUpdated PathOutcome = "updated"
	// PathRemoved means a stale managed leaf was removed.
	PathRemoved PathOutcome = "removed"
	// PathFailed means reconciliation of the path failed.
	PathFailed PathOutcome = "failed"
)

type PathResult

type PathResult struct {
	Path    string
	Outcome PathOutcome
	Err     error
}

PathResult is the exact per-path reconciliation result.

type Pipeline

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

Pipeline is an ordered sequence of process steps whose output-to-input dataflow is fully explicit: a step may consume a prior step's captured output as its standard input, but every such edge must reference a capture already produced by an earlier step. There is no implicit shell pipe. Pipelines are added only where the classified inventory requires ordered dataflow.

func NewPipeline

func NewPipeline(steps ...ProcessStep) (Pipeline, error)

NewPipeline validates ordering and output-to-input dataflow. A previous-output standard input must reference a capture produced by a strictly earlier step, and every capture name must be produced exactly once.

func (Pipeline) IsValid

func (p Pipeline) IsValid() bool

func (Pipeline) Steps

func (p Pipeline) Steps() []ProcessStep

Steps returns a defensive copy of the ordered pipeline steps.

type ProcessStep

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

ProcessStep is one step in a pipeline. It wraps a RunProcess and is the unit of ordered, dataflow-linked execution.

func NewProcessStep

func NewProcessStep(process RunProcess) (ProcessStep, error)

NewProcessStep wraps a validated RunProcess as a pipeline step.

func (ProcessStep) IsValid

func (s ProcessStep) IsValid() bool

func (ProcessStep) Process

func (s ProcessStep) Process() RunProcess

type PublicationFS

type PublicationFS interface {
	// Stat reports the node at an absolute-or-root-relative path. A missing path
	// returns NodeAbsent with a nil error.
	Stat(path string) (PublishedNode, error)
	// ReadFile reads the exact content of a regular file.
	ReadFile(path string) ([]byte, error)
	// WriteFile writes exact content to a regular file with mode, replacing any
	// prior regular-file content.
	WriteFile(path string, content []byte, mode fs.FileMode) error
	// MkdirAll ensures a directory (and parents) exists with mode.
	MkdirAll(path string, mode fs.FileMode) error
	// Remove removes exactly the node at path.
	Remove(path string) error
}

PublicationFS is the injected filesystem seam publication reconciles against. Production wires an os-backed implementation; tests wire an in-memory fake. The reconciliation policy lives entirely in the publisher, never in an implementation of this seam.

type PublishReport

type PublishReport struct {
	Results          []PathResult
	ManifestReplaced bool
}

PublishReport is the exact result of a publication. Results holds one entry per reconciled or attempted path in deterministic path order. ManifestReplaced reports whether the sidecar was advanced to the new confirmed manifest; on any payload failure it stays false and the last confirmed manifest is retained.

func Publish

func Publish(tree ir.RenderedTree, payloadRoot string, filesystem PublicationFS) (PublishReport, error)

Publish reconciles a fully validated immutable RenderedTree into the publisher-owned payloadRoot and advances a hidden same-parent sidecar (.<payload-root>.pasture-manifest.json) only after the payload verifies. It creates, updates, and removes to reach exact final path/type/mode/content equality with the tree, including stale-leaf removal. It verifies payload first and replaces the sidecar last, reports exact per-path partial results, retains the last confirmed manifest on failure, and lets the same tree retry resume from old-or-desired matching states. It fails before any mutation on a sidecar collision or unsafe type, on unrelated drift, or when a partial prior publish is unreconciled and the desired tree has changed. It never claims rollback or an atomic directory swap.

Publish must only ever be called with a RenderedTree from a successful compile+lower+native-load; a caller must not invoke it on any such failure.

func (PublishReport) Failed

func (r PublishReport) Failed() bool

Failed reports whether any path result failed.

type PublishedNode

type PublishedNode struct {
	Type NodeType
	Mode fs.FileMode
}

PublishedNode is the observed state of one filesystem path.

type RemoteRef

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

RemoteRef is the exact destination ref a push updates (for example refs/heads/main). It carries no whitespace, control, or glob characters.

func NewRemoteRef

func NewRemoteRef(value string) (RemoteRef, error)

NewRemoteRef validates an exact remote ref name.

func (RemoteRef) Equal

func (r RemoteRef) Equal(other RemoteRef) bool

func (RemoteRef) IsValid

func (r RemoteRef) IsValid() bool

func (RemoteRef) String

func (r RemoteRef) String() string

type RemoteState

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

RemoteState is the observed state of a remote ref: whether it exists and, if so, its exact commit. It is the read-back a guarded push verifies against.

func AbsentRemoteState

func AbsentRemoteState() RemoteState

AbsentRemoteState reports that the remote ref does not exist.

func PresentRemoteState

func PresentRemoteState(commit CommitOID) RemoteState

PresentRemoteState reports that the remote ref exists at commit.

func (RemoteState) Commit

func (s RemoteState) Commit() (CommitOID, bool)

Commit returns the remote commit and true when the ref exists.

func (RemoteState) Present

func (s RemoteState) Present() bool

Present reports whether the remote ref exists.

type RepositoryID

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

RepositoryID is the opaque identity of one git repository an effect acts on.

func NewRepositoryID

func NewRepositoryID(value string) (RepositoryID, error)

NewRepositoryID validates a repository identity.

func (RepositoryID) Equal

func (r RepositoryID) Equal(other RepositoryID) bool

func (RepositoryID) IsValid

func (r RepositoryID) IsValid() bool

func (RepositoryID) String

func (r RepositoryID) String() string

type RepositoryPusher

type RepositoryPusher interface {
	// VerifyLocalObject confirms the local repository holds commit and that it
	// carries exactly tree. It returns an actionable error otherwise.
	VerifyLocalObject(repository RepositoryID, commit CommitOID, tree TreeDigest) error
	// PushExact performs only the commit:remoteRef update under the expected-old
	// guard. An error here is not by itself failure: the caller re-reads the
	// remote to decide, so an "already up to date" rejection can still be a
	// verified idempotent replay.
	PushExact(repository RepositoryID, commit CommitOID, remoteRef RemoteRef, expectedOld ExpectedOldOID) error
	// ReadRemote re-reads the current state of remoteRef.
	ReadRemote(repository RepositoryID, remoteRef RemoteRef) (RemoteState, error)
}

RepositoryPusher is the injected seam that performs the three primitive git operations a guarded push composes: verifying the exact local object, performing only the CommitOID:RemoteRef update, and re-reading the remote. Production wires this to a git executable; tests wire a fake. ReadRemote is called twice by the algorithm below — once before the push, to probe whether the remote already holds the exact target, and once after, to verify it. The guarded-push algorithm — verify, probe, push, re-read, and only-then construct the proof — lives entirely in GuardedPushExactCommit, never in an implementation of this seam.

type RunProcess

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

RunProcess is one modeled process execution. Every field is a typed operand, never a shell string: the executable is dispatched with execve semantics and arguments are passed verbatim. It is opaque and constructor-owned, and is an Effect variant classified native.

func NewRunProcess

func NewRunProcess(spec RunProcessSpec) (RunProcess, error)

NewRunProcess validates every operand and builds an immutable RunProcess. An unset Stdin/Stdout/Stderr defaults to no input and discarded output; Exit defaults to success-only; Directory is required.

func (RunProcess) Arguments

func (p RunProcess) Arguments() []Argument

func (RunProcess) Classify

func (p RunProcess) Classify() RuntimeClass

func (RunProcess) Directory

func (p RunProcess) Directory() WorkingDirectoryRef

func (RunProcess) Effects

func (p RunProcess) Effects() ir.EffectSet

func (RunProcess) Environment

func (p RunProcess) Environment() []EnvBinding

func (RunProcess) Executable

func (p RunProcess) Executable() ExecutableRef

func (RunProcess) Exit

func (p RunProcess) Exit() ExitExpectation

func (RunProcess) IsValid

func (p RunProcess) IsValid() bool

func (RunProcess) Stderr

func (p RunProcess) Stderr() OutputRef

func (RunProcess) Stdin

func (p RunProcess) Stdin() InputRef

func (RunProcess) Stdout

func (p RunProcess) Stdout() OutputRef

type RunProcessSpec

type RunProcessSpec struct {
	Executable  ExecutableRef
	Arguments   []Argument
	Directory   WorkingDirectoryRef
	Environment []EnvBinding
	Stdin       InputRef
	Stdout      OutputRef
	Stderr      OutputRef
	Exit        ExitExpectation
	Effects     ir.EffectSet
}

RunProcessSpec is the typed, non-opaque input to NewRunProcess. It exists so callers name operands by field rather than by positional argument order.

type RuntimeClass

type RuntimeClass string

RuntimeClass is the closed classification a runtime contract assigns to every modeled effect. It is deliberately exhaustive: every effect this package can construct answers Classify with exactly one of these, so a lowerer can never encounter an effect it has no explicit plan for.

const (
	// RuntimeClassNative is executed directly by the host harness runtime.
	RuntimeClassNative RuntimeClass = "native"
	// RuntimeClassParentMediated is executed by the parent orchestrator on the
	// effect's behalf (for example a guarded landing push).
	RuntimeClassParentMediated RuntimeClass = "parent-mediated"
	// RuntimeClassSemanticInstruction is lowered to a semantic instruction the
	// agent must carry out (for example repository-policy commit guidance).
	RuntimeClassSemanticInstruction RuntimeClass = "semantic-instruction"
	// RuntimeClassUnsupported names a construct that has no modeled semantics
	// and must become a dedicated operation before it can be lowered. It never
	// renders through an opaque shell string.
	RuntimeClassUnsupported RuntimeClass = "unsupported"
)

func (RuntimeClass) IsValid

func (c RuntimeClass) IsValid() bool

type ShellConstruct

type ShellConstruct string

ShellConstruct is the closed set of shell constructs Pasture deliberately does not model as processes. Each must become a dedicated semantic operation; a lowerer may never smuggle one through an opaque `sh -c` string.

const (
	// ShellExpansion is variable, command, arithmetic, or tilde expansion.
	ShellExpansion ShellConstruct = "expansion"
	// ShellControlOperator is a control operator such as &&, ||, ;, &, !, or a
	// command separator such as a newline or tab.
	ShellControlOperator ShellConstruct = "control-operator"
	// ShellRedirection is stream redirection such as >, >>, <, or 2>&1.
	ShellRedirection ShellConstruct = "redirection"
	// ShellGlobbing is filename globbing such as *, ?, or [...].
	ShellGlobbing ShellConstruct = "globbing"
	// ShellPipeline is an unstructured `|` shell pipeline. Structured dataflow
	// uses Pipeline with explicit captures instead.
	ShellPipeline ShellConstruct = "pipeline"
	// ShellGrouping is subshell or brace-group syntax such as (...) or {...}.
	ShellGrouping ShellConstruct = "grouping"
	// ShellQuoting is quoting or escaping such as "...", '...', or a backslash
	// escape.
	ShellQuoting ShellConstruct = "quoting"
	// ShellComment is a shell comment introduced by #.
	ShellComment ShellConstruct = "comment"
)

func ClassifyShellConstruct

func ClassifyShellConstruct(fragment string) (ShellConstruct, error)

ClassifyShellConstruct inspects a raw shell fragment for constructs outside the modeled process/pipeline algebra. If it finds one, it returns the classified construct and an actionable error naming the owner, location, and fix. It never produces an `sh -c` rendering: an unsupported construct must be promoted to a dedicated semantic operation instead. A fragment with no unsupported construct returns ("", nil).

Detection proceeds in two passes. First, a small set of compound multi-character idioms (such as "2>&1" or "$(") are checked so common fragments classify with a higher-fidelity token in their error message. Second, a per-rune fallback scans the fragment against shellMetaCharacterConstruct — the same shellMetaCharacters set ExecutableRef enforces — so every metacharacter is classified even if it never appears in the compound list above. A command separator (newline or tab) is checked alongside the compound idioms: it is not itself a shellMetaCharacters entry (ExecutableRef instead rejects it via containsControl), but it carries the same command-separator semantics as ';' and so must not silently classify clean.

type TreeDigest

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

TreeDigest is a full, lowercase-hex git tree object id naming the exact tree a commit must carry.

func NewTreeDigest

func NewTreeDigest(value string) (TreeDigest, error)

NewTreeDigest validates a full tree object id.

func (TreeDigest) Equal

func (t TreeDigest) Equal(other TreeDigest) bool

func (TreeDigest) IsValid

func (t TreeDigest) IsValid() bool

func (TreeDigest) String

func (t TreeDigest) String() string

type VerifiedGuardedPush

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

VerifiedGuardedPush is the opaque, process-local proof that a guarded landing push reached its exact target. It is deliberately not a constructible exported struct: the only producer is GuardedPushExactCommit, which constructs one only after re-reading the remote and confirming it holds the exact commit. Its zero value is invalid. It has read-only accessors and Validate, and no codec: MarshalJSON deliberately fails so the proof can never serialize or leave the application process. A consumer (the authoritative task package) imports this package and hands the proof straight to its protected commit; the public wire form of a landing carries only an event id and the outcome, never this proof.

func GuardedPushExactCommit

func GuardedPushExactCommit(input GuardedPushInput, pusher RepositoryPusher) (VerifiedGuardedPush, error)

GuardedPushExactCommit is the one landing push. It verifies the exact local object, probes the remote before pushing (best-effort — an unreadable probe never blocks the push), performs only the CommitOID:RemoteRef update through pusher, re-reads the remote, and constructs the opaque VerifiedGuardedPush only when that re-read confirms the remote holds the exact commit. This re-read gate is the sole safety invariant and is unconditional: no outcome label ever bypasses it. A remote that already held the exact commit before this call ran is an idempotent replay success, labeled distinctly from a fresh push; a stale, racing, or different ref returns no proof. It makes no SQLite or multi-repository atomicity claim.

func (VerifiedGuardedPush) Commit

func (v VerifiedGuardedPush) Commit() CommitOID

func (VerifiedGuardedPush) MarshalJSON

func (v VerifiedGuardedPush) MarshalJSON() ([]byte, error)

MarshalJSON always fails: the proof is a process-local capability, not data. This guarantees the proof can never be serialized, logged as a token, or leave the application process by accident.

func (VerifiedGuardedPush) Outcome

func (VerifiedGuardedPush) RemoteRef

func (v VerifiedGuardedPush) RemoteRef() RemoteRef

func (VerifiedGuardedPush) Repository

func (v VerifiedGuardedPush) Repository() RepositoryID

func (VerifiedGuardedPush) Tree

func (VerifiedGuardedPush) Validate

func (v VerifiedGuardedPush) Validate() error

Validate reports whether this is a genuine verified proof. A zero value, or a value with a zero/invalid repository, commit, tree, ref, or outcome, is rejected. Only GuardedPushExactCommit can produce a value that passes.

type WorkingDirectoryKind

type WorkingDirectoryKind string

WorkingDirectoryKind distinguishes an explicit path working directory from an assignment-local worktree reference.

const (
	WorkingDirectoryPath     WorkingDirectoryKind = "path"
	WorkingDirectoryWorktree WorkingDirectoryKind = "worktree"
)

type WorkingDirectoryRef

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

WorkingDirectoryRef is the closed sum of the two ways a process may name its working directory: an explicit owned path, or an assignment-local worktree reference minted by the #38 IR. It is opaque and constructor-owned.

func NewPathWorkingDirectory

func NewPathWorkingDirectory(path OwnedPath) (WorkingDirectoryRef, error)

NewPathWorkingDirectory names the working directory by an exact owned path.

func NewWorktreeWorkingDirectory

func NewWorktreeWorkingDirectory(ref ir.WorktreeRef) (WorkingDirectoryRef, error)

NewWorktreeWorkingDirectory names the working directory by a worktree ref.

func (WorkingDirectoryRef) IsValid

func (w WorkingDirectoryRef) IsValid() bool

func (WorkingDirectoryRef) Kind

func (WorkingDirectoryRef) Path

func (w WorkingDirectoryRef) Path() (OwnedPath, bool)

Path returns the owned path and true when the working directory is a path.

func (WorkingDirectoryRef) Worktree

func (w WorkingDirectoryRef) Worktree() (ir.WorktreeRef, bool)

Worktree returns the worktree ref and true when the working directory is a worktree reference.

Jump to

Keyboard shortcuts

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