execrecovery

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package execrecovery implements the execution-recovery contract (R1–R6) used by fixture conformance tests and by direct-execution wait paths.

Index

Constants

View Source
const (
	CodeIdempotencyConflict   = "idempotency_conflict"
	CodeIdempotencyInProgress = "idempotency_in_progress"
)

Codes from KeeperHub/keeperhub lib/idempotency.ts idempotencyEarlyResponse. Both map to HTTP 409; only `code` distinguishes them.

View Source
const FixtureVersion = 1
View Source
const IdempotencyHeader = "Idempotency-Key"

Variables

This section is empty.

Functions

func ConclusiveFailedReceipt

func ConclusiveFailedReceipt(status string) bool

ConclusiveFailedReceipt reports a chain-answered failure (lib/web3/verify-receipt.ts CONCLUSIVE_STATUSES minus success).

func NewIdempotencyKey

func NewIdempotencyKey() (string, error)

NewIdempotencyKey returns a random UUID-like key for a single write intent. Callers that retry the same intent across process restarts must persist or derive a stable key instead (see docs.keeperhub.com/api/direct-execution).

func NonSuccessReceipt

func NonSuccessReceipt(r Receipt) bool

NonSuccessReceipt is true when a receipt exists and is not explicitly successful.

func ResolveIdempotencyKey

func ResolveIdempotencyKey(explicit string) (string, error)

ResolveIdempotencyKey returns explicit if non-empty, otherwise a new key.

Types

type ConflictError

type ConflictError struct {
	Body IdempotencyBody
	Key  string
}

ConflictError is a 409 idempotency_conflict.

func (ConflictError) Error

func (e ConflictError) Error() string

type DirectStatus

type DirectStatus struct {
	ExecutionID     string    `json:"executionId"`
	Status          string    `json:"status"`
	Type            string    `json:"type"`
	TransactionHash *string   `json:"transactionHash"`
	TransactionLink *string   `json:"transactionLink"`
	Result          any       `json:"result"`
	Error           *string   `json:"error"`
	CreatedAt       string    `json:"createdAt"`
	CompletedAt     *string   `json:"completedAt"`
	Receipts        []Receipt `json:"receipts,omitempty"`
}

DirectStatus is the flat wire shape of GET /api/execute/{id}/status. Canonical type: cmd/execute aliases this as ExecStatusResponse.

type Fixture

type Fixture struct {
	Name                 string          `json:"-"`
	Version              int             `json:"version"`
	Kind                 Kind            `json:"kind"`
	Rule                 string          `json:"rule"`
	HTTPStatus           int             `json:"httpStatus"`
	RequireChainEvidence bool            `json:"requireChainEvidence"`
	Expect               Outcome         `json:"expect"`
	Response             json.RawMessage `json:"response"`
	ResponseRaw          string          `json:"responseRaw,omitempty"`
	Note                 string          `json:"note,omitempty"`
}

Fixture is one conformance case loaded from testdata/execution_recovery_v1.

func LoadFixtureDir

func LoadFixtureDir(dir string) ([]Fixture, error)

LoadFixtureDir loads every versioned *.json fixture that is not a sequence.

func (Fixture) DecodeResponse

func (f Fixture) DecodeResponse() (DirectStatus, error)

DecodeResponse unmarshals the flat DirectStatus wire body.

func (Fixture) Sample

func (f Fixture) Sample() Sample

Sample converts a fixture into a Classify input.

type IdempotencyBody

type IdempotencyBody struct {
	Error               string  `json:"error"`
	Code                string  `json:"code"`
	Retryable           *bool   `json:"retryable"`
	OriginalExecutionID *string `json:"originalExecutionId"`
}

IdempotencyBody is the 409 JSON from idempotencyEarlyResponse.

func ParseIdempotencyBody

func ParseIdempotencyBody(body []byte) (IdempotencyBody, bool)

ParseIdempotencyBody decodes a 409 body. ok is true when `code` is one of the two idempotency codes, or when retryable is present as a fallback.

func (IdempotencyBody) IsConflict

func (b IdempotencyBody) IsConflict() bool

IsConflict is true when the key is bound to a different payload. The client must fail closed and must not rotate the key.

func (IdempotencyBody) IsInProgress

func (b IdempotencyBody) IsInProgress() bool

IsInProgress is true when the same key is already processing. The client must retry that key and must not mint a new one.

type InProgressTimeoutError

type InProgressTimeoutError struct {
	Key string
}

InProgressTimeoutError is returned when 409 idempotency_in_progress outlives the wait budget. The same key must be reused on the next attempt.

func (InProgressTimeoutError) Error

func (e InProgressTimeoutError) Error() string

type Kind

type Kind string

Kind labels how a fixture relates to production.

observed: a response the current handler can emit. defensive: a client-side invariant against a body KEEP-966 makes unreachable. classifier: exercises a classifier option the shipped CLI does not set.

const (
	KindObserved   Kind = "observed"
	KindDefensive  Kind = "defensive"
	KindClassifier Kind = "classifier"
)

type Options

type Options struct {
	// RequireChainEvidence is a classifier-only option used by fixtures.
	// The shipped CLI wait paths do not set it. When true, completed
	// without a verified successful receipt is Failure.
	RequireChainEvidence bool
}

Options controls classification strictness.

type Outcome

type Outcome string

Outcome is the classified result of one status observation.

const (
	OutcomePending Outcome = "pending"
	OutcomeSuccess Outcome = "success"
	OutcomeFailure Outcome = "failure"
	// OutcomeUnconfirmed is broadcast-but-unreadable. It is neither success nor
	// failure: the transaction may already be on chain. Callers stop waiting and
	// report it; they must not poll it through and must not resubmit.
	OutcomeUnconfirmed  Outcome = "unconfirmed"
	OutcomeMalformed    Outcome = "malformed"
	OutcomeRateLimited  Outcome = "rate_limited"
	OutcomeUnrecognized Outcome = "unrecognized"
)

func Classify

func Classify(sample Sample, opts Options) (Outcome, string)

Classify maps one status observation to an Outcome.

Direct-execution statuses are pending|running|unconfirmed|completed|failed (app/api/execute/_lib/types.ts). Workflow run statuses (success|error|cancelled) belong to a different API and must not be fed here — see Vocabulary().

`unconfirmed` maps to OutcomeUnconfirmed, not OutcomePending: the server keeps reconciling that row, but a client must stop waiting on it rather than poll to a failure the chain never reported.

An unknown future status is OutcomeUnrecognized (never success, never malformed) so a server addition does not look like a corrupt body.

type Receipt

type Receipt struct {
	Hash          string  `json:"hash"`
	ChainID       *int    `json:"chainId,omitempty"`
	Network       string  `json:"network,omitempty"`
	Verified      bool    `json:"verified"`
	ReceiptStatus string  `json:"receiptStatus"`
	BlockNumber   *int64  `json:"blockNumber,omitempty"`
	GasUsed       *string `json:"gasUsed,omitempty"`
	VerifiedAt    string  `json:"verifiedAt"`
}

Receipt is GET /api/execute/{id}/status receipts[] (DirectExecutionReceiptEntry in KeeperHub/keeperhub).

receiptStatus values from lib/web3/verify-receipt.ts: success | reverted | not_found | timeout | safe_inner_failure. verifiedAt is required on the server type. chainId is optional.

func FirstBlockingReceipt

func FirstBlockingReceipt(receipts []Receipt) *Receipt

FirstBlockingReceipt returns the first receipt that must not be treated as success.

type Sample

type Sample struct {
	HTTPStatus int
	Body       []byte
}

Sample is one HTTP observation of an execution status endpoint.

type SequenceFixture

type SequenceFixture struct {
	Name    string         `json:"name"`
	Version int            `json:"version"`
	Kind    Kind           `json:"kind"`
	Rule    string         `json:"rule"`
	Steps   []SequenceStep `json:"steps"`
}

SequenceFixture exercises multi-poll recovery (R6).

func LoadSequence

func LoadSequence(path string) (SequenceFixture, error)

LoadSequence loads a multi-step sequence fixture.

func LoadSequenceDir

func LoadSequenceDir(dir string) ([]SequenceFixture, error)

LoadSequenceDir loads every *.sequence.json fixture in dir.

type SequenceStep

type SequenceStep struct {
	HTTPStatus           int             `json:"httpStatus"`
	RequireChainEvidence bool            `json:"requireChainEvidence"`
	Expect               Outcome         `json:"expect"`
	Response             json.RawMessage `json:"response"`
	ResponseRaw          string          `json:"responseRaw,omitempty"`
}

SequenceStep is one observation in a multi-response cold-start sequence.

func (SequenceStep) Sample

func (s SequenceStep) Sample() Sample

Sample converts a sequence step into a Classify input.

type Vocabulary

type Vocabulary struct {
	Surface  string
	Pending  []string
	Terminal []string
}

Vocabulary documents which status strings belong to which API surface. Direct-execution and workflow-run statuses must not be mixed.

Pending and Terminal are client wait semantics: Pending means keep polling, Terminal means stop waiting and report. Terminal is not a claim that the server will never change the row again.

func DirectExecutionVocabulary

func DirectExecutionVocabulary() Vocabulary

DirectExecutionVocabulary is GET /api/execute/{id}/status (app/api/execute/_lib/types.ts ExecutionStatus).

`unconfirmed` is listed Terminal in the client sense only. The server documents it as non-terminal and a reconciliation sweep settles it to completed or failed; clients still stop there so that an unreadable receipt never becomes a re-run that broadcasts twice.

func WorkflowRunVocabulary

func WorkflowRunVocabulary() Vocabulary

WorkflowRunVocabulary is GET /api/workflows/executions/{id}/status.

Jump to

Keyboard shortcuts

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