contracts

package module
v0.0.0-...-79ff044 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2026 License: GPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package contracts defines the stable interfaces between MuxCore and its modules. These interfaces form the v1 contract boundary.

STABILITY GUARANTEE (v1)

All exported types, interfaces, constants, and functions in this package are frozen for the v1 lifetime. Breaking changes — including but not limited to adding or removing interface methods, changing struct fields, or modifying constant values — require a v2 major version.

The following are NOT covered by this guarantee:

  • Types explicitly marked "RESERVED" or "Experimental" in their doc comment
  • The `eventschema.go` file (reserved for future schema-evolution support)

IMPLEMENTING CONTRACTS

Modules implement these interfaces and register with core via gRPC. Each contract has a corresponding capability string for runtime discovery (see capabilities.go). Modules do not import core binary — they only import this contracts package and the proto-generated Go types.

IMPORT PATH

This package is released as a standalone Go module so that module authors can depend on it without pulling in the full core dependency tree:

require github.com/Muxcore-Media/core/pkg/contracts v1.0.0

All feedback: https://github.com/Muxcore-Media/core/issues

Index

Constants

View Source
const (
	CapabilitySecrets         = "secrets"
	CapabilityDatabase        = "database"
	CapabilityCache           = "cache"
	CapabilityCacheLocal      = "cache.local"
	CapabilityMetrics         = "metrics"
	CapabilityTracing         = "tracing"
	CapabilityCircuitBreaker  = "circuitbreaker"
	CapabilityConfigWatcher   = "config.watcher"
	CapabilityDeadLetter      = "deadletter"
	CapabilityCallPolicy      = "call.policy"
	CapabilityPublishPolicy   = "publish.policy"
	CapabilityIdentity        = "identity"
	CapabilityLogging         = "logging"
	CapabilityRetry           = "retry"
	CapabilityIdempotency     = "idempotency"
	CapabilityFeatureFlags    = "feature.flags"
	CapabilitySerialization   = "serialization"
	CapabilityEncryption      = "encryption"
	CapabilityDistributedLock = "distributed.lock"
	CapabilityDataRedaction   = "data.redaction"
	CapabilityEventStore      = "event.store"
	CapabilityInputValidate   = "input.validate"
	CapabilityWorkflowEngine  = "workflow.engine"
	CapabilitySpoolResolver   = "spool.resolver"
	CapabilityScheduler       = "scheduler"
	CapabilityHealthMonitor   = "health.monitor"
	CapabilityBackup          = "backup"

	// Worker pool capabilities.
	CapabilityWorkerPool = "worker.pool"
	// CapabilityExecutorPrefix is the prefix for executor discovery.
	// Modules handling task type "download" advertise "executor.download".
	CapabilityExecutorPrefix = "executor."

	// Auth/security capabilities.
	CapabilityAuth        = "auth"
	CapabilityAuthorizer  = "authorizer"
	CapabilityRateLimiter = "ratelimit"
)

Capability strings for all discoverable services. Use these constants with Registry.FindByCapability and in ModuleInfo.Capabilities to avoid silent typo failures.

View Source
const (
	EventClusterNodeJoined    = "cluster.node.joined"
	EventClusterNodeLeft      = "cluster.node.left"
	EventClusterNodeDegraded  = "cluster.node.degraded"
	EventClusterLeaderChanged = "cluster.leader.changed"
)

Cluster event types for the event bus.

View Source
const (
	EventModuleRegistered   = "module.registered"
	EventModuleUnregistered = "module.unregistered"
	EventModuleDegraded     = "module.degraded"
	EventConfigReloaded     = "config.reloaded"
)

Module-lifecycle event types — the only domain event types core knows about. Cluster events are in cluster.go. All other event types are in contract repos.

View Source
const (
	SafeContentTypeJSON     = "application/json"
	SafeContentTypeProtobuf = "application/x-protobuf"
	SafeContentTypeMsgpack  = "application/msgpack"
)

SafeSerializationTypes enumerates content types that are considered safe for deserialization. These formats do not support code-execution gadgets or type-confusion attacks in their standard Go implementations.

Formats NOT in this list (e.g., "application/yaml", "application/gob", "application/x-java-serialized-object") MUST NOT be supported by SerializationProvider implementations unless explicit sandboxing is applied and documented.

View Source
const (
	EventTapestryStarted   = "tapestry.started"
	EventTapestryCompleted = "tapestry.completed"
	EventTapestryFailed    = "tapestry.failed"
	EventTapestryCancelled = "tapestry.cancelled"
	EventTapestryPaused    = "tapestry.paused"
	EventTapestryResumed   = "tapestry.resumed"
	EventStepStarted       = "tapestry.step.started"
	EventStepCompleted     = "tapestry.step.completed"
	EventStepFailed        = "tapestry.step.failed"
)

Tapestry lifecycle event types — defined here so both core and modules can reference them without a separate contract repo for workflow.

View Source
const EventSchemaVersion = "v1"

EventSchemaVersion is the schema version for event payloads. Defined for future typed-payload support. Currently the event bus uses raw []byte Payload and this constant is not consumed at runtime.

View Source
const EventStorageTierTransition = "storage.tier.transition"

EventStorageTierTransition is emitted when an object moves between tiers.

Variables

View Source
var ErrCallDenied = errors.New("call policy: access denied")

ErrCallDenied is returned when a call policy provider denies access. This is distinct from ErrCallNoPolicy which means no provider is registered.

View Source
var ErrCallNoPolicy = errors.New("call policy: no provider registered — calls are denied by default")

ErrCallNoPolicy is returned when no CallPolicyProvider is registered. In production, the mesh MUST reject cross-module calls when no provider is present rather than defaulting to open mode. This error signals that the deployment is missing a required security component.

View Source
var ErrCircuitOpen = errors.New("circuit breaker is open")

ErrCircuitOpen is returned by CircuitBreaker.Execute when the circuit is open and the call is rejected without execution.

View Source
var ErrDatabaseCredentialExposure = errors.New("database: credential passed as raw string — use DatabaseParams instead")

ErrDatabaseCredentialExposure is a sentinel error that DatabaseProvider implementations SHOULD return if they detect that credentials were passed as a raw connection string. This enables CI lint rules to detect unsafe database initialization.

View Source
var ErrLockHeld = errors.New("distributed lock: key is already held")

ErrLockHeld is returned by DistributedLockProvider.Acquire when the requested key is already locked by another client.

View Source
var ErrMigrationTargetNotFound = errors.New("database: target migration version not found")

ErrMigrationTargetNotFound is returned by DatabaseProvider.Rollback when the targetVersion does not exist in the provider's migration list.

View Source
var ErrNoCandidates = errors.New("load balancing: no candidate nodes available")

ErrNoCandidates is returned by LBStrategy.Pick when the candidate list is empty.

View Source
var ErrNotFound = errors.New("object not found")

ErrNotFound is returned by storage providers when a key does not exist. Use errors.Is(err, contracts.ErrNotFound) to check.

View Source
var ErrRollbackNotSupported = errors.New("database: rollback not supported by this provider")

ErrRollbackNotSupported is returned by DatabaseProvider.Rollback when the provider does not implement rollback functionality.

Functions

func ReplyEventType

func ReplyEventType(eventType string) string

ReplyEventType returns the event type that Request/reply handlers listen on. Responders publish a reply event with this type; Request waits for it.

bus.Subscribe(ctx, contracts.ReplyEventType("media.requested"), handler)

func SensitiveLogFieldNames

func SensitiveLogFieldNames() []string

SensitiveLogFieldNames returns a copy of the curated list of field name prefixes that commonly carry credentials, tokens, or PII. Redaction providers and logging implementations SHOULD use this list as a default deny-set.

This list is not exhaustive — implementations may extend it based on their domain. The convention is lowercase field names as they appear in structured log fields.

Types

type Action

type Action string

Action represents an operation a caller wants to perform. Standard verbs: "create", "read", "update", "delete", "list", "execute".

const (
	ActionCreate  Action = "create"
	ActionRead    Action = "read"
	ActionUpdate  Action = "update"
	ActionDelete  Action = "delete"
	ActionList    Action = "list"
	ActionExecute Action = "execute"
)

type AtomicMovable

type AtomicMovable interface {
	AtomicMove(ctx context.Context, src, dst string) error
}

type AuditEntry

type AuditEntry struct {
	ID         string
	Timestamp  time.Time
	Actor      string            // user ID, "system", or module ID
	Action     string            // e.g., "http.request", "module.registered", "media.requested"
	Resource   string            // e.g., "/api/movies", "admin-ui", "Inception"
	ResourceID string            // UUID of the affected resource, if applicable
	Details    map[string]string // arbitrary context — MUST NOT contain credentials or PII
	TraceID    string
	NodeID     string
	// PrevEntryHash is the SHA-256 hash of the chronologically previous audit entry.
	// This forms a tamper-evident hash chain. Zero value for the first entry in a log.
	PrevEntryHash string
	// Signature is an optional HMAC-SHA256 over the entry fields using a root key.
	// Enables verification that the entry was produced by an authorized audit logger.
	// Empty if the audit logger does not support cryptographic signing.
	Signature string
}

AuditEntry is a single audit log record.

type AuditFilter

type AuditFilter struct {
	Actor    string
	Action   string
	Resource string
	From     time.Time
	To       time.Time
	TraceID  string
	// VerifyChain, when true, instructs Query to validate the hash chain
	// of returned entries and exclude or flag entries with broken links.
	VerifyChain bool
}

AuditFilter narrows audit queries.

type AuditLogger

type AuditLogger interface {
	// Log records an audit entry.
	//
	// SECURITY: Details MUST NOT contain credentials, tokens, or PII.
	// The caller is responsible for redacting sensitive data before
	// calling Log. Use DataRedactionProvider if the details map is
	// built from untrusted input.
	Log(ctx context.Context, entry AuditEntry) error

	// Query returns entries matching the filter.
	Query(ctx context.Context, filter AuditFilter) ([]AuditEntry, error)

	// Export writes all entries in the given format (json, csv).
	Export(ctx context.Context, format string) (io.ReadCloser, error)

	// VerifyChainIntegrity performs a standalone integrity check on the
	// audit log hash chain in the given time range. Unlike Query with
	// VerifyChain=true, this method does not return entry data — it only
	// returns the verification result. This enables independent integrity
	// audits without exposing audit content to the verifier.
	//
	// If the provider does not support hash chains, this method returns
	// a result with Valid=true and TotalEntries=0 (no chain to verify).
	VerifyChainIntegrity(ctx context.Context, from, to time.Time) (ChainVerificationResult, error)

	// VerifyAll performs a full integrity check across all surviving
	// rotated audit log files and the current active file, verifying
	// the hash chain and HMAC signatures across file boundaries.
	//
	// Entries in the deleted oldest rotated file (if any) are reported
	// in UnverifiableCount. The active file is snapshotted at call time;
	// entries written concurrently are not included.
	VerifyAll(ctx context.Context) (ChainVerificationResult, error)
}

AuditLogger records and queries audit entries.

type AuthProvider

type AuthProvider interface {
	// Authenticate verifies credentials and returns a session if valid.
	// The returned Session.Token is the bearer token for subsequent
	// Validate calls.
	Authenticate(ctx context.Context, credentials Credentials) (Session, error)

	// Validate checks whether a token is still valid and returns the
	// associated session. Returns an error if the token is expired,
	// revoked, or malformed.
	//
	// SECURITY: The token parameter MUST NOT be logged. Use a
	// cryptographically safe prefix (first 8 chars of SHA-256) for
	// audit trail references.
	Validate(ctx context.Context, token string) (Session, error)

	// Revoke invalidates a token so it can no longer be used for
	// Validate calls. Already-established sessions are not affected
	// until their next Validate.
	Revoke(ctx context.Context, token string) error
}

AuthProvider authenticates callers and validates existing sessions.

SECURITY: Implementations MUST NOT log tokens. The token parameter on Validate and the Token field on Session are sensitive material. If you need to log authentication events, use AuditLogger with redacted token references (e.g., a SHA-256 prefix of the token).

type Authorizer

type Authorizer interface {
	// Can performs a permission check using a flat (action, resource) pair.
	//
	// SECURITY: The session parameter contains a raw token. Authorizer
	// implementations MUST NOT log or store the full Session struct.
	// Use session.Safe() if identity information is needed for audit.
	Can(ctx context.Context, session Session, action string, resource string) (bool, error)
}

Authorizer checks whether a session is permitted to perform an action on a resource.

For resource-level checks with ABAC support, implement the optional ResourceAuthorizer interface alongside Authorizer. Callers that need resource-level authorization type-assert to ResourceAuthorizer and fall back to Authorizer.Can if it's not supported.

type BackupInfo

type BackupInfo struct {
	ID        string
	Timestamp time.Time
	Size      int64
	Modules   []string // module IDs included in the backup
}

BackupInfo describes a completed backup.

type BackupProvider

type BackupProvider interface {
	// CreateBackup captures state from all registered Backupable modules.
	CreateBackup(ctx context.Context) (BackupInfo, error)
	// Restore restores state from a previous backup.
	Restore(ctx context.Context, backupID string) error
	// ListBackups returns all available backups.
	ListBackups(ctx context.Context) ([]BackupInfo, error)
	// DeleteBackup removes a stored backup.
	DeleteBackup(ctx context.Context, backupID string) error
}

BackupProvider is implemented by backup modules (backup-local, backup-s3, etc.)

type Backupable

type Backupable interface {
	// ExportState returns serialized state for backup.
	ExportState(ctx context.Context) ([]byte, error)
	// ImportState restores state from a backup.
	ImportState(ctx context.Context, data []byte) error
}

Backupable is implemented by modules that have state to back up.

type CacheLayer

type CacheLayer interface {
	// Get returns cached data for the given key. The bool indicates a cache hit.
	Get(ctx context.Context, key string) ([]byte, bool)
	// Set caches data for the given key.
	Set(ctx context.Context, key string, data []byte) error
	// Invalidate removes all cached entries whose key has the given prefix.
	Invalidate(ctx context.Context, prefix string) error
}

CacheLayer is an optional read-through cache for the storage orchestrator. Unlike CacheProvider (distributed caches for application state), CacheLayer provides local caching for storage objects. Implemented by cache-memory and similar modules. Core discovers a CacheLayer at bootstrap; if none is found, the orchestrator operates without a cache.

type CacheProvider

type CacheProvider interface {
	// Get retrieves a value by key. Returns nil, nil if the key does not exist.
	Get(ctx context.Context, key string) ([]byte, error)
	// Set stores a value with an optional TTL. Zero TTL means no expiration.
	Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
	// Delete removes one or more keys.
	Delete(ctx context.Context, keys ...string) error
	// Exists checks whether a key exists.
	Exists(ctx context.Context, key string) (bool, error)
	// Incr atomically increments an integer key by delta and returns the new value.
	Incr(ctx context.Context, key string, delta int64) (int64, error)
	// CompareAndSwap atomically replaces oldValue with newValue at key.
	// Returns true if the swap succeeded (key held oldValue), false otherwise.
	// A nil oldValue matches a non-existent key.
	CompareAndSwap(ctx context.Context, key string, oldValue, newValue []byte) (bool, error)
	// Lock acquires a distributed lock on a key. Returns a Lock handle.
	// If the key is already locked, returns an error immediately (non-blocking).
	Lock(ctx context.Context, key string, ttl time.Duration) (LockHandle, error)
	// Publish sends a message on a pub/sub channel.
	Publish(ctx context.Context, channel string, msg []byte) error
	// Subscribe returns a channel that receives messages published on the given channel.
	Subscribe(ctx context.Context, channel string) (<-chan []byte, error)
}

CacheProvider is implemented by cache modules (cache-redis, cache-valkey, etc.) to provide ephemeral state, distributed locks, and pub/sub. Core defines the contract; modules provide the driver.

type CallPolicyProvider

type CallPolicyProvider interface {
	// AllowCall returns (true, nil) if caller is permitted to invoke method on target.
	// Returns (false, nil) if access is denied, or (false, error) if the policy engine
	// encountered an error (transient failure, configuration issue, etc.).
	AllowCall(ctx context.Context, callerModuleID, targetModuleID, method string) (bool, error)
}

CallPolicyProvider determines whether one module is allowed to call another. Implemented by modules that define inter-module access control. The mesh client consults this before dispatching calls.

SECURITY: When no CallPolicyProvider is registered, the mesh MUST deny all cross-module calls and return ErrCallNoPolicy. This is a change from the previous behavior where the default was open mode. Deployments that want open mode must register an explicit permissive policy provider.

Discovered via FindByCapability(CapabilityCallPolicy). Only one policy provider is consulted — if multiple register, the first found wins.

type ChainVerificationResult

type ChainVerificationResult struct {
	// Valid is true if the entire chain is intact with no broken links.
	Valid bool
	// TotalEntries is the number of entries in the verified range.
	TotalEntries int
	// UnverifiableCount is the number of entries that existed in the oldest
	// rotated file which was deleted before verification. These entries
	// cannot be verified and are not counted in TotalEntries.
	UnverifiableCount int
	// BrokenLinks is the list of entry IDs where the PrevEntryHash does
	// not match the computed hash of the previous entry.
	BrokenLinks []string
	// FirstBrokenAt is the timestamp of the first detected break, or
	// the zero time if no breaks were found.
	FirstBrokenAt time.Time
}

ChainVerificationResult reports the outcome of a hash-chain integrity check.

type CircuitBreaker

type CircuitBreaker interface {
	// Execute runs fn within the circuit identified by key.
	// If the circuit is open, returns ErrCircuitOpen immediately.
	// If fn returns an error, the failure is recorded against the circuit.
	Execute(ctx context.Context, key string, fn func(context.Context) error) error

	// State returns the current state of the circuit identified by key.
	State(key string) CircuitState
}

CircuitBreaker protects downstream calls from cascading failures. When a downstream module degrades, the circuit opens and calls fail fast instead of waiting for timeouts. After a configurable cooldown (module-defined), the circuit transitions to half-open to test recovery.

Modules that call other modules via Mesh.Call() wrap those calls in Execute() to gain circuit breaking without implementing it themselves.

type CircuitState

type CircuitState string

CircuitState represents the current state of a circuit breaker.

const (
	// CircuitClosed — normal operation, requests flow through.
	CircuitClosed CircuitState = "closed"
	// CircuitOpen — failing, requests are rejected immediately with ErrCircuitOpen.
	CircuitOpen CircuitState = "open"
	// CircuitHalfOpen — testing if the downstream has recovered.
	// A single success transitions back to closed; a failure re-opens.
	CircuitHalfOpen CircuitState = "half_open"
)

type Cluster

type Cluster interface {
	// Start joins or forms a cluster. If no seed nodes are reachable,
	// the node starts a new single-node cluster.
	Start(ctx context.Context) error

	// Stop gracefully leaves the cluster.
	Stop(ctx context.Context) error

	// Members returns all current cluster members.
	Members() []NodeInfo

	// Leader returns the current leader, or nil if unknown.
	Leader() *NodeInfo

	// LocalNode returns information about this node.
	LocalNode() NodeInfo

	// Events returns a channel that emits cluster membership changes.
	Events() <-chan ClusterEvent

	// Health checks whether the cluster is operational.
	Health(ctx context.Context) error

	// FindNodesByLabel returns all nodes with the given label value.
	FindNodesByLabel(ctx context.Context, label, value string) []NodeInfo

	// FindNodesByModule returns all nodes running the given module.
	FindNodesByModule(ctx context.Context, moduleID string) []NodeInfo
}

Cluster manages node membership, leader election, and peer discovery.

type ClusterEvent

type ClusterEvent struct {
	Type     ClusterEventType
	Node     NodeInfo
	LeaderID string
}

ClusterEvent is emitted when cluster membership changes.

type ClusterEventType

type ClusterEventType string

ClusterEventType describes the kind of membership change.

const (
	ClusterNodeJoined    ClusterEventType = "node.joined"
	ClusterNodeLeft      ClusterEventType = "node.left"
	ClusterNodeDegraded  ClusterEventType = "node.degraded"
	ClusterLeaderChanged ClusterEventType = "leader.changed"
)

type ConfigWatcher

type ConfigWatcher interface {
	// OnChange registers a handler that fires when modules matching the
	// given capability string are added or removed. Returns a cancel
	// function to stop watching. The handler receives no arguments —
	// the module is expected to re-query the registry for current state.
	OnChange(ctx context.Context, capability string, handler func()) (cancel func())
}

ConfigWatcher notifies modules when infrastructure services change at runtime. Modules subscribe by capability string; when a new module registers or an existing one disappears, registered handlers fire.

Modules use this instead of polling the registry. Example:

watcher.OnChange(ctx, "secrets", func() {
    entries := reg.FindByCapability("secrets")
    if len(entries) > 0 {
        secrets = entries[0].Module.(contracts.SecretsProvider)
    }
})

ConfigWatcher is discovered via FindByCapability("config.watcher"). If no module implements it, modules fall back to polling or subscribe to module.registered/module.unregistered events directly.

type ContractDeclaration

type ContractDeclaration struct {
	Repo      string // Go module path of the contract package
	Version   string // semantic version tag (e.g. "v1.0.0")
	Interface string // Go interface name the module implements (e.g. "Downloader")
}

ContractDeclaration describes a typed contract that a module implements. Modules declare these in their Info() so consumers can verify compatibility before attempting type assertions. The marketplace uses these to detect incompatibilities between installed modules and prospective modules.

type Counter

type Counter interface {
	Inc()
	Add(delta float64)
}

Counter is a monotonically increasing metric.

type CredentialType

type CredentialType string

CredentialType enumerates well-known authentication schemes. Implementations MUST validate the type against this set to prevent credential-type confusion attacks (e.g., an attacker sending a password in a "token"-typed credential).

const (
	CredentialTypePassword CredentialType = "password"
	CredentialTypeToken    CredentialType = "token"
	CredentialTypeCert     CredentialType = "cert"
	CredentialTypeAPIKey   CredentialType = "api-key"
)

type Credentials

type Credentials struct {
	Type string
	Data []byte
}

Credentials carries authentication material to the AuthProvider. Type identifies the credential scheme and Data holds the opaque credential payload.

SECURITY: Implementations MUST NOT log the Data field. Callers MUST NOT include credentials in structured log fields, audit entries, or event payloads. Use the SecretsProvider contract to store and retrieve credentials instead of passing them through application code.

Backward-compat: Credentials.Type remains string (not CredentialType) so existing providers that use custom type strings continue to work. New implementations SHOULD validate against the CredentialType constants.

type DataRedactionProvider

type DataRedactionProvider interface {
	// Redact returns a new map with sensitive values replaced according
	// to the given rules. The input map is not modified. Rules are
	// provider-specific identifiers; the provider silently ignores
	// rules it doesn't recognize.
	Redact(ctx context.Context, data map[string]any, rules []string) (map[string]any, error)
}

DataRedactionProvider redacts sensitive data from structured payloads before they are logged, audited, or stored. This contract exists so modules never write PII (emails, IP addresses, tokens, personal data) to plaintext logs or audit trails.

Modules call Redact on any map[string]any before passing it to StructuredLogger, AuditLogger, or any persistent storage. The provider applies configured rules to replace sensitive values with redacted placeholders.

The rules parameter is an opaque list of rule identifiers that the provider interprets. Common patterns: field-name matching ("email", "password"), path expressions ("user.address.street"), regex patterns ("/\\d{3}-\\d{2}-\\d{4}/"), or category tags ("pii", "phi"). The provider documents which rule syntax it supports.

This contract is provider-agnostic: a module that calls Redact works identically whether the backend uses regex, field-name allowlists, an external DLP service, or a future redaction engine.

If no DataRedactionProvider is registered, Redact returns the input unchanged — modules degrade without nil checks but SHOULD document that redaction is inactive.

type DatabaseParams

type DatabaseParams struct {
	// Driver is the database driver name (e.g., "postgres", "sqlite3").
	Driver string
	// Host is the database server address (host:port or socket path).
	Host string
	// Database is the database name.
	Database string
	// User is the database username.
	User string
	// Password is the database password. Leave empty for passwordless auth.
	//
	// SECURITY: Never log this field. Fetch the password from
	// SecretsProvider at connection time rather than storing it in
	// application state.
	Password string
	// Extra carries driver-specific connection parameters (e.g., sslmode,
	// connect_timeout). These are appended to the DSN after the core params.
	// Keys and values in Extra must not contain credentials.
	Extra map[string]string
}

DatabaseParams separates connection parameters from credentials. Use this struct with DatabaseProvider.Open instead of passing a raw connection string. This prevents accidental credential exposure in logs, stack traces, and configuration serialization.

SECURITY: The Password field is a plain string — implementations MUST NOT log DatabaseParams or any field within it. If the database driver supports credential-free authentication (IAM, workload identity, certificate-based auth), prefer those methods and leave Password empty.

type DatabaseProvider

type DatabaseProvider interface {
	// Open initializes the database connection using separated connection
	// parameters. This isolates credentials from connection metadata,
	// reducing the risk of accidental credential exposure.
	//
	// Implementations SHOULD return ErrDatabaseCredentialExposure if
	// the caller attempts to embed credentials in Extra.
	Open(ctx context.Context, params DatabaseParams) error

	// Close gracefully shuts down the database connection.
	Close(ctx context.Context) error
	// Health checks whether the database is reachable.
	Health(ctx context.Context) error
	// Exec runs a statement that modifies data (INSERT, UPDATE, DELETE, DDL).
	//
	// SECURITY: Callers MUST use parameterized queries. Never concatenate
	// user input into the query string. The args ...any parameter supports
	// standard SQL placeholders ($1, ?, :name). Consider using
	// InputValidator with "sql:<param-count>" schema for additional
	// injection protection.
	Exec(ctx context.Context, query string, args ...any) (int64, error)
	// Query runs a read query and returns a row iterator.
	//
	// SECURITY: Same parameterization requirement as Exec. All user
	// input MUST be passed via args, never interpolated into query.
	Query(ctx context.Context, query string, args ...any) (Rows, error)
	// Transaction runs fn inside a database transaction, committing on success and rolling back on error.
	Transaction(ctx context.Context, fn func(Tx) error) error
	// Migrate applies ordered schema migrations. Implementations track which migrations
	// have already been applied and skip those.
	//
	// SECURITY: Migration SQL (Up/Down strings) is trusted schema code.
	// Implementations SHOULD verify migration content against a known
	// checksum or signature before execution when operating in production.
	Migrate(ctx context.Context, migrations []Migration) error

	// Rollback reverts schema migrations down to the given target version
	// by applying Down SQL in reverse version order. targetVersion of 0
	// rolls back all migrations (empty schema). Returns nil if no rollback
	// is needed (current version <= targetVersion). Returns
	// ErrMigrationTargetNotFound if targetVersion does not exist in the
	// migrations list. Returns ErrRollbackNotSupported if the provider
	// does not implement rollback.
	//
	// Implementations MUST apply Down SQL within transactions and track
	// the current schema version in their migrations tracking table.
	// They MUST reject rollback past version 0 (dropping below baseline).
	Rollback(ctx context.Context, targetVersion int) error
}

DatabaseProvider is implemented by database modules (database-postgres, database-sqlite, etc.) to provide persistent storage for modules. Core defines the contract; modules provide the driver.

Discovered via FindByCapability(CapabilityDatabase).

type DeadLetterEntry

type DeadLetterEntry struct {
	Event       Event
	HandlerName string
	Error       string
	FailedAt    time.Time
	RetryCount  int
}

DeadLetterEntry stores a failed event with its error context.

type DeadLetterProvider

type DeadLetterProvider interface {
	// Store records a failed event delivery. Called by the event bus
	// or by modules that want explicit dead-letter handling.
	Store(ctx context.Context, event Event, handlerName string, err error) error

	// Replay returns failed events for the given handler since the given time.
	// Sorted by FailedAt ascending.
	Replay(ctx context.Context, handlerName string, since time.Time) ([]DeadLetterEntry, error)

	// Discard removes a failed event from the dead letter store after
	// the issue has been resolved.
	Discard(ctx context.Context, eventID string) error
}

DeadLetterProvider stores events that failed to process so they can be inspected, replayed, or discarded. Modules that handle critical events (workflow steps, downloads, imports) can configure a dead letter provider to prevent silent data loss when a handler transiently fails.

DeadLetterProvider is discovered via FindByCapability("deadletter"). If no module implements it, failed events are logged and dropped.

type DistributedLockHandle

type DistributedLockHandle interface {
	// Unlock releases the lock. Safe to call multiple times.
	Unlock(ctx context.Context) error

	// Renew extends the lock's TTL without releasing and re-acquiring.
	// Useful for long-running operations where the initial TTL would expire
	// before completion. Returns ErrLockHeld if the lock was lost (e.g.,
	// network partition caused the backend to expire it).
	Renew(ctx context.Context, ttl time.Duration) error
}

DistributedLockHandle represents an acquired distributed lock. Callers must call Unlock when done, or Renew to extend the lease for long-running operations.

type DistributedLockProvider

type DistributedLockProvider interface {
	// Acquire attempts to acquire a lock for the given key with a TTL.
	// Returns (nil, ErrLockHeld) if the key is already locked.
	// Returns (nil, ctx.Err()) if the context is cancelled before acquisition.
	// The returned handle must be Unlock()ed when the critical section completes.
	Acquire(ctx context.Context, key string, ttl time.Duration) (DistributedLockHandle, error)
}

DistributedLockProvider provides standalone distributed locking. This is distinct from CacheProvider.Lock which ties locking to a cache instance. Modules that need coordination (leader election, singleton workers, migration gating, split-brain fencing) use this contract without needing to stand up a cache.

This contract is provider-agnostic: a module that calls Acquire works identically whether the backend is Redis, etcd, Consul, Postgres advisory locks, or a future coordination service.

Acquire is non-blocking by design. If the lock is held, it returns ErrLockHeld immediately. Callers that want blocking behavior compose this with RetryProvider.Execute.

If no DistributedLockProvider is registered, Acquire always succeeds (single-node mode) — modules degrade gracefully without nil checks.

type EncryptionProvider

type EncryptionProvider interface {
	// Encrypt encrypts plaintext and returns self-describing ciphertext.
	// The returned bytes include key version metadata so Decrypt can
	// identify the correct key even after rotation.
	Encrypt(ctx context.Context, plaintext []byte) ([]byte, error)

	// Decrypt decrypts ciphertext that was produced by Encrypt.
	// The provider reads key metadata from the ciphertext to select
	// the correct decryption key, including keys from previous rotations.
	Decrypt(ctx context.Context, ciphertext []byte) ([]byte, error)

	// RotateKey initiates key rotation. After rotation, new Encrypt calls
	// use the new key. Old keys remain available for Decrypt indefinitely —
	// previously encrypted data does not need re-encryption.
	//
	// SECURITY: Implementations that do NOT support rotation (static-key
	// implementations) MUST return an error from this method. Production
	// deployments SHOULD use a provider that supports rotation.
	RotateKey(ctx context.Context) error

	// Available reports whether encryption is configured and operational.
	// Returns false if no provider is registered or the provider is in a
	// degraded state. The fabric SHOULD use this to enforce encryption
	// requirements at startup.
	Available() bool
}

EncryptionProvider handles envelope encryption for sensitive data at rest. Modules call Encrypt before storing sensitive data and Decrypt after retrieving it. The provider manages key material, rotation, and versioning internally — modules never touch raw keys.

The ciphertext produced by Encrypt is self-describing: it carries key metadata so Decrypt can identify which key was used, even after rotation.

This contract is provider-agnostic: a module that calls Encrypt/Decrypt works identically whether the backend uses AES-GCM with local keys, a cloud KMS (AWS KMS, GCP KMS), HashiCorp Vault transit engine, or a future encryption service. The security posture is determined by the provider implementation, not by module code.

SECURITY: Production deployments MUST register an EncryptionProvider. If no EncryptionProvider is registered, the fabric SHOULD refuse to start in production mode. Development and CI environments may operate without encryption. Use the Available() method to check at runtime.

type Event

type Event struct {
	ID        string
	Type      string
	Source    string
	TraceID   string
	Payload   []byte
	Metadata  map[string]string
	Timestamp time.Time
}

Event is the envelope for all inter-module communication. Type is a dotted string like "module.registered" or "media.requested". Event type constants and payload schemas are defined by contract repos, not by core. Core only defines the module-lifecycle event types (below). Cluster-lifecycle events are defined in cluster.go.

Payload is opaque bytes. Producers and consumers agree on the encoding (typically JSON) for a given event type. The EventSchemaVersion constant is reserved for future typed-payload support; for v1, callers marshal and unmarshal Payload themselves.

Timestamp is set by the publisher. Consumers should treat it as advisory.

type EventBus

type EventBus interface {
	Publish(ctx context.Context, event Event) error

	// Subscribe registers a handler for the given event type.
	// Use "*" to subscribe to all events.
	// Returns a cancel function that removes the subscription when called.
	// The cancel function is safe to call multiple times.
	Subscribe(ctx context.Context, eventType string, handler EventHandler) (cancel func(), err error)

	// Request publishes an event and waits for a reply on ReplyEventType(event.Type).
	Request(ctx context.Context, event Event, timeout time.Duration) (Event, error)

	// SubscribeModule registers a handler tagged with a module identifier.
	// Returns a cancel function that removes this subscription when called.
	// Use UnsubscribeAll for bulk removal of all subscriptions owned by a module.
	SubscribeModule(ctx context.Context, moduleID, eventType string, handler EventHandler) (cancel func(), err error)

	// UnsubscribeAll removes all subscriptions tagged with the given module ID.
	// If moduleID is empty, this is a no-op. Used by module lifecycle management
	// during shutdown to prevent handlers from receiving events after the
	// module has stopped.
	UnsubscribeAll(ctx context.Context, moduleID string) error
}

EventBus is the core message bus. All module communication flows through it.

type EventHandler

type EventHandler func(ctx context.Context, event Event) error

EventHandler is a callback invoked when a matching event is published.

type EventStore

type EventStore interface {
	// Append writes events to a stream and returns their assigned sequence
	// numbers. Events in a single Append call are atomic — either all
	// are written or none are. Returns the starting sequence number for
	// the batch and an error if the write fails.
	//
	// The first event in a new stream gets sequence 1.
	Append(ctx context.Context, stream string, events []Event) (firstSequence int64, err error)

	// Read returns events from a stream starting at fromSequence (inclusive).
	// limit caps the number of events returned. Pass 0 for no limit
	// (provider default). Returns events in ascending sequence order.
	// Returns an empty slice if fromSequence is beyond the stream end.
	Read(ctx context.Context, stream string, fromSequence int64, limit int) ([]EventStoreEntry, error)

	// Subscribe returns a channel that receives new events appended to
	// the stream starting from fromSequence. The channel closes when ctx
	// is cancelled. Events are delivered in sequence order.
	//
	// To catch up on existing events before live ones, call Read first
	// to get historical events, then Subscribe from the last sequence + 1.
	Subscribe(ctx context.Context, stream string, fromSequence int64) (<-chan EventStoreEntry, error)

	// Streams returns the names of all known streams.
	Streams(ctx context.Context) ([]string, error)
}

EventStore provides a durable, append-only event log. This is distinct from EventBus which handles fire-and-forget pub/sub. EventStore is for event sourcing: state is reconstructed by replaying all events in a stream from the beginning.

Streams are logical partitions — typically one per aggregate or entity type ("user-abc123", "order-456", "module.metrics"). Append guarantees that events within a stream are ordered by sequence number.

This contract is provider-agnostic: a module that calls Append/Read works identically whether the backend is PostgreSQL, Kafka, NATS JetStream, an in-memory log, or a future event store.

If no EventStore is registered, Append is a no-op (returns nil sequence) and Read/Subscribe return empty — modules that only need pub/sub use EventBus; modules that need event sourcing require an EventStore.

type EventStoreEntry

type EventStoreEntry struct {
	// Stream is the logical partition this event belongs to.
	Stream string

	// Sequence is the monotonically increasing position within the stream.
	// The first event in a stream has sequence 1.
	Sequence int64

	// Event is the stored event with type, source, payload, and metadata.
	Event Event

	// StoredAt is when the event was appended to the store.
	StoredAt time.Time

	// Extra carries provider-specific extensions (e.g., partition info,
	// checksum, storage tier).
	Extra map[string]any
}

EventStoreEntry is a persisted event with its stream position.

type Executor

type Executor interface {
	CanHandle(taskType string) bool
	Execute(ctx context.Context, task WorkerTask) (result []byte, err error)
}

Executor is implemented by modules that can run tasks of a given type.

type FeatureFlagProvider

type FeatureFlagProvider interface {
	// IsEnabled checks whether a feature flag is enabled for the caller
	// in the given context. The context carries identity for percentage-based
	// rollouts and targeting rules. defaultValue is returned when no provider
	// is registered or the flag is not defined.
	IsEnabled(ctx context.Context, flag string, defaultValue bool) bool

	// GetVariant returns the assigned variant for a multivariate flag.
	// Useful for A/B testing where a flag has more than two states.
	// defaultValue is returned when no provider is registered or the
	// flag is not defined.
	GetVariant(ctx context.Context, flag string, defaultValue string) string
}

FeatureFlagProvider evaluates feature flags for gradual rollouts, kill switches, and A/B testing. Modules call IsEnabled before activating new code paths; the provider evaluates the flag against the caller's identity (via context) and any configured rules.

This contract is provider-agnostic: a module that calls IsEnabled works identically whether the backend is a config file, LaunchDarkly, a database table, or a future feature flag service.

If no FeatureFlagProvider is registered, IsEnabled returns defaultValue and GetVariant returns defaultValue — modules degrade gracefully without nil checks.

type Gauge

type Gauge interface {
	Set(value float64)
	Inc()
	Dec()
	Add(delta float64)
}

Gauge is a metric that can increase and decrease.

type Hardlinkable

type Hardlinkable interface {
	Hardlink(ctx context.Context, src, dst string) error
}

type HealthMonitor

type HealthMonitor interface {
	// StartMonitoring begins periodic health checking. The monitor calls Health()
	// on every registered module at the configured interval and publishes
	// events on the bus for any degraded modules.
	StartMonitoring(ctx context.Context, reg Registry, bus EventBus) error

	// Stop gracefully stops the health monitor.
	Stop(ctx context.Context) error
}

HealthMonitor runs periodic health checks on all registered modules and publishes module.degraded events for unhealthy modules. Core starts the HealthMonitor at bootstrap if one is discovered from the registry. If no module implements this contract, periodic health monitoring is skipped (modules still report via /health endpoint).

type Histogram

type Histogram interface {
	Observe(value float64)
}

Histogram observes values and tracks distribution.

type IdempotencyProvider

type IdempotencyProvider interface {
	// Store records that a key has been processed and caches the result.
	// Returns (true, nil) if the key was new — this is the first occurrence.
	// Returns (false, nil) if the key was already stored — this is a duplicate.
	// The result is cached for ttl; after expiry the key may be evicted.
	Store(ctx context.Context, key string, result []byte, ttl time.Duration) (bool, error)

	// Exists checks whether a key has been previously stored and not yet expired.
	// Returns true if the key exists, false otherwise.
	Exists(ctx context.Context, key string) (bool, error)

	// Result retrieves the cached result for a previously stored key.
	// Returns (nil, nil) if the key does not exist or has expired.
	// This allows a duplicate request to receive the same response
	// as the original without re-executing the operation.
	Result(ctx context.Context, key string) ([]byte, error)
}

IdempotencyProvider prevents duplicate processing of requests. When a module receives a request that must not be processed more than once (e.g., payment capture, order creation), it generates an idempotency key and checks this provider before acting.

This contract is provider-agnostic: a module that calls Store/Exists works identically whether the backend is in-memory, Redis, a database table, or a future storage mechanism.

If no IdempotencyProvider is registered, Store always returns true (treated as first occurrence) and Exists always returns false — modules degrade gracefully without needing nil checks.

This contract pairs with RetryProvider. Retries may deliver the same logical request multiple times; IdempotencyProvider ensures the side effects only happen once.

type Identity

type Identity struct {
	// ID is the unique identifier for this caller (user ID, service account ID).
	ID string

	// Kind describes the type of identity (e.g., "user", "service", "api-key").
	Kind string

	// Roles are the authorization roles assigned to this identity.
	Roles []string

	// Claims carries provider-specific claims extracted from the auth token.
	// For JWT this is the decoded payload. For API keys this may be scopes.
	//
	// SECURITY: May contain sensitive data. Redact before logging.
	Claims map[string]any

	// Extra carries provider-specific extensions that consumers can interpret.
	//
	// SECURITY: May contain sensitive data. Redact before logging.
	Extra map[string]any
}

Identity represents the caller extracted from an authentication context. Fields are intentionally broad — the identity provider populates whatever it can determine, and downstream consumers interpret what they understand.

SECURITY: Claims and Extra carry provider-specific data that may include sensitive information from auth tokens (JWT payloads, API key metadata). These fields MUST be treated as potentially sensitive:

  • NEVER serialize a full Identity to logs without redaction.
  • NEVER include Identity in event payloads unless the event is explicitly an auth/identity event with access controls.
  • Use SafeInfo() when passing identity data to subsystems that do not need provider-specific claims.

The SafeInfo method strips Claims and Extra, retaining only the typed fields that Authorizer needs for permission checks.

func (Identity) SafeInfo

func (id Identity) SafeInfo() Identity

SafeInfo returns a copy of the Identity with Claims and Extra stripped. Use this when passing identity to subsystems that do not need provider-specific data (logging, metrics, events, workflows).

type IdentityProvider

type IdentityProvider interface {
	// ExtractIdentity extracts the caller identity from the given context.
	// Returns (nil, nil) if no identity is present (unauthenticated request).
	// Returns an error only if identity extraction itself fails (e.g., invalid
	// token format), not if the request is simply unauthenticated.
	ExtractIdentity(ctx context.Context) (*Identity, error)
}

IdentityProvider extracts caller identity from context. Modules call this to determine who is making a request before passing that identity to the Authorizer for permission checks.

This contract is provider-agnostic: a module that calls ExtractIdentity works identically whether the backend is JWT validation, API key lookup, mTLS certificate extraction, or a future protocol.

SECURITY: When no IdentityProvider is registered, the system MUST apply a deny-by-default access policy. Anonymous access (no identity) should only be permitted for explicitly public endpoints. The fabric should refuse to start in production mode without an IdentityProvider — see EnforcedIdentityProvider.

Discovered via FindByCapability("identity"). If no module implements this contract, the fabric treats all requests as unauthenticated (nil identity). Modules MUST check for nil identity and apply their own access policy. The recommended safe default is to deny access when identity is nil unless the endpoint is explicitly marked as public.

type InputValidator

type InputValidator interface {
	// Validate checks the given data against the named schema and returns
	// a result indicating pass/fail plus any sanitized output.
	//
	// The schema parameter follows the conventions above. If the schema is
	// not recognised, implementations should return a ValidationResult with
	// Valid=false and an error entry explaining the unknown schema, rather
	// than returning an error — this allows callers to fall back gracefully.
	//
	// SECURITY: The schema string MUST be validated before use (see type docs).
	Validate(ctx context.Context, data []byte, schema string) (ValidationResult, error)

	// SupportedSchemas returns the list of schema identifiers this validator
	// can handle. Used for capability discovery so callers can determine at
	// registration time whether a validator meets their needs.
	SupportedSchemas() []string
}

InputValidator performs centralized input validation for the MuxCore fabric. Modules implement this contract to provide schema-aware validation that other modules can delegate to, rather than duplicating validation logic.

Schema conventions:

"json:<schema-name>"   — JSON Schema validation (e.g., "json:user-create")
"regex:<pattern>"      — Regex-based validation (e.g., "regex:^[a-z]+$")
"sql:<param-count>"    — SQL injection-safe parameter binding (e.g., "sql:3")

SECURITY: The schema parameter is caller-controlled. Implementations MUST:

  • Validate the schema string format before interpretation.
  • Reject schemas with path-traversal characters (../, /, etc.) to prevent access to unintended schema files or namespaces.
  • Apply a limit on schema name length to prevent resource exhaustion.
  • Never treat the schema string as a file path without sanitization.

Schema names should match the pattern: ^[a-z][a-z0-9_.:-]{0,127}$

Modules discover registered validators via the registry and call SupportedSchemas() to check which schemas are available before calling Validate. If no InputValidator is registered, modules handle validation themselves (degrade gracefully).

Discovered via FindByCapability("input.validate"). If multiple validators register, the first found is consulted. Validators may internally delegate to other validators for schemas they do not support.

type LBStrategy

type LBStrategy interface {
	// Pick returns the index of the selected candidate from candidates.
	// candidates is guaranteed to have at least one entry.
	// Returns ErrNoCandidates if candidates is empty.
	Pick(ctx context.Context, candidates []NodeInfo) (int, error)
}

LBStrategy selects a target node from a set of candidates for load-balanced cross-node module routing. Implementations must be safe for concurrent use.

type LeaderChangedPayload

type LeaderChangedPayload struct {
	PreviousLeader string `json:"previous_leader"`
	NewLeader      string `json:"new_leader"`
}

LeaderChangedPayload is the payload for cluster.leader.changed events.

type LockHandle

type LockHandle interface {
	// Unlock releases the lock.
	Unlock(ctx context.Context) error
}

LockHandle represents an acquired distributed lock.

type LogLevel

type LogLevel string

LogLevel describes the severity of a log message.

const (
	LogLevelDebug LogLevel = "debug"
	LogLevelInfo  LogLevel = "info"
	LogLevelWarn  LogLevel = "warn"
	LogLevelError LogLevel = "error"
)

type MeshHandler

type MeshHandler interface {
	// HandleCall processes a cross-module method invocation.
	// method is an arbitrary string the caller and handler agree on.
	// payload is the JSON-encoded request body.
	// Returns the JSON-encoded response or an error.
	HandleCall(ctx context.Context, method string, payload []byte) ([]byte, error)
}

MeshHandler is implemented by modules that want to receive cross-module gRPC calls. The mesh server routes incoming Call(targetModule, method, payload) requests to the target module's HandleCall method.

Modules register themselves as handlers during Start():

deps.Mesh.RegisterHandler("my-module", myHandler)

type MetricsProvider

type MetricsProvider interface {
	// Counter creates or returns a counter with the given name and labels.
	Counter(name string, labels map[string]string) Counter
	// Gauge creates or returns a gauge with the given name and labels.
	Gauge(name string, labels map[string]string) Gauge
	// Histogram creates or returns a histogram with the given name, labels, and buckets.
	Histogram(name string, labels map[string]string, buckets []float64) Histogram
}

MetricsProvider exposes application metrics. Modules implement this to provide Prometheus, Datadog, or other metrics backends. Modules that want to expose metrics call these methods to register and update metrics. If no MetricsProvider is registered, metric calls are no-ops.

type Migration

type Migration struct {
	Version int
	Name    string
	Up      string // SQL to apply
	// Down is SQL to revert the migration. Used by Rollback to undo
	// schema changes in reverse version order.
	Down string
}

Migration represents a versioned schema migration.

type Module

type Module interface {
	Info() ModuleInfo
	Init(ctx context.Context) error
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
	Health(ctx context.Context) error
}

type ModuleDegradedPayload

type ModuleDegradedPayload struct {
	ModuleID string `json:"module_id"`
	Error    string `json:"error"`
}

ModuleDegradedPayload is the payload for module.degraded events.

type ModuleEntry

type ModuleEntry struct {
	Info   ModuleInfo
	State  ModuleState
	Module Module
}

type ModuleInfo

type ModuleInfo struct {
	ID           string
	Name         string
	Version      string
	Roles        []string // module-defined role strings; core imposes no taxonomy
	Description  string
	Author       string
	Capabilities []string              // granular capability strings for routing/discovery
	Contracts    []ContractDeclaration // typed contracts this module implements
	DependsOn    []string              // module IDs that must be initialized before this module starts. Cycles detected by Registry.StartupOrder().
	// MinCoreVersion is the minimum core version required by this module.
	// Uses SemVer (e.g., "1.2.0"). Empty means compatible with any version.
	// Core rejects modules whose MinCoreVersion is greater than the running
	// core version or targets a different major version.
	MinCoreVersion string
	// HTTPAddr is the address where this module serves HTTP, if any.
	// Example: ":8085" or "0.0.0.0:9200". Leave empty if the module does not
	// expose HTTP. Other modules discover this via ModuleEntry.Info.HTTPAddr
	// after a successful FindByCapability or Resolve call.
	HTTPAddr string
}

type ModuleKind

type ModuleKind string

ModuleKind is a user-defined string that categorizes a module's role. Core has no opinion about what kinds exist — modules and consumers define them. Common conventions (defined in contract repos, not here): "auth", "downloader", "indexer", "media_manager", "playback", "storage", "workflow", "transcoder". The WorkflowEngine is discovered via "workflow.engine".

type ModuleMeshClient

type ModuleMeshClient interface {
	// Call invokes a method on the target module. If the target is registered
	// locally, the call is dispatched in-process with zero network overhead.
	// If the target is on a remote node, the call goes over gRPC.
	Call(ctx context.Context, targetModule, method string, payload []byte) ([]byte, error)

	// RegisterHandler registers a local module to receive incoming Call requests.
	// Only call this during module Start(). Modules that don't receive calls
	// don't need to register.
	RegisterHandler(moduleID string, handler MeshHandler)
}

ModuleMeshClient is the interface modules use to call other modules. It abstracts whether the target is local (in-process) or remote (gRPC network call). Modules dial core's gRPC ModuleMesh service to obtain a client.

type ModuleRegisteredPayload

type ModuleRegisteredPayload struct {
	ModuleID string `json:"module_id"`
	Version  string `json:"version"`
}

ModuleRegisteredPayload is the payload for module.registered events.

type ModuleState

type ModuleState string
const (
	ModuleStateRegistered ModuleState = "registered"
	ModuleStateStarting   ModuleState = "starting"
	ModuleStateRunning    ModuleState = "running"
	ModuleStateDegraded   ModuleState = "degraded"
	ModuleStateStopping   ModuleState = "stopping"
	ModuleStateStopped    ModuleState = "stopped"
)

type ModuleUnregisteredPayload

type ModuleUnregisteredPayload struct {
	ModuleID string `json:"module_id"`
}

ModuleUnregisteredPayload is the payload for module.unregistered events.

type NodeInfo

type NodeInfo struct {
	ID        string
	GRPCAddr  string
	HTTPAddr  string
	Labels    map[string]string
	ModuleIDs []string
	// ModuleHealth maps module ID to health status.
	// Empty string means healthy. Non-empty is the last health check error.
	ModuleHealth map[string]string
}

NodeInfo describes a node in the cluster.

type NodeJoinedPayload

type NodeJoinedPayload struct {
	NodeID   string `json:"node_id"`
	GRPCAddr string `json:"grpc_addr"`
	HTTPAddr string `json:"http_addr"`
}

NodeJoinedPayload is the payload for cluster.node.joined events.

type NodeLeftPayload

type NodeLeftPayload struct {
	NodeID string `json:"node_id"`
}

NodeLeftPayload is the payload for cluster.node.left events.

type ObjectInfo

type ObjectInfo struct {
	Key          string
	Size         int64
	ContentType  string
	ETag         string
	LastModified time.Time
	Metadata     map[string]string
}

type Permission

type Permission string

Permission represents a named permission in the authorization system. The string format is "<domain>.<verb>" or "<domain>.<resource>.<verb>", e.g. "storage.read", "media.movies.delete", "admin.*".

Wildcard support:

  • "*" matches all permissions (superuser)
  • "domain.*" matches all permissions within a domain
  • "domain.resource.*" matches all permissions on a specific resource

type PublishPolicyProvider

type PublishPolicyProvider interface {
	// CanPublish returns (true, nil) if the caller is permitted to publish
	// events of the given type. Returns (false, nil) if publishing is denied.
	CanPublish(ctx context.Context, callerID, eventType string) (bool, error)
}

PublishPolicyProvider determines whether a caller is authorized to publish events of a given type. Implemented by modules that define event-level access control. The event bus consults this before dispatching.

SECURITY: When no PublishPolicyProvider is registered, the event bus MUST deny all event publication. This is a change from the previous behavior where the default was open mode. Deployments that want open mode must register an explicit permissive policy provider.

Discovered via FindByCapability(CapabilityPublishPolicy).

For resource-level event authorization, implement the optional ResourcePublishPolicyProvider interface. The event bus will type-assert and use the richer interface when available.

type RateLimiterProvider

type RateLimiterProvider interface {
	// Allow checks whether a request from the given key (typically IP) is allowed.
	// Returns true if the request should proceed, false if it should be rate-limited.
	Allow(ctx context.Context, key string) bool

	// Enabled returns whether rate limiting is active.
	Enabled() bool
}

RateLimiterProvider is implemented by rate limiter modules (ratelimit-tokenbucket, etc.) to provide request rate limiting to the API server middleware chain. Core discovers a RateLimiterProvider at bootstrap and injects it into the middleware. If no module implements this contract, rate limiting is disabled (open mode).

type RedactingLogger

type RedactingLogger interface {
	StructuredLogger

	// IsRedacting reports whether this logger automatically applies
	// redaction to all fields before writing to sinks.
	IsRedacting() bool
}

RedactingLogger is an optional extension that guarantees all log output is redacted. Implementations that embed automatic redaction can declare this interface so that callers can skip manual redaction.

Modules MAY type-assert their StructuredLogger to RedactingLogger to determine if manual redaction is necessary.

type Registry

type Registry interface {
	FindByRole(role string) []ModuleEntry
	FindByCapability(cap string) []ModuleEntry
	SupportsCapability(moduleID, cap string) bool
	Resolve(id string) (ModuleEntry, error)
	ListAll() []ModuleEntry

	// StartupOrder returns module IDs in dependency-respecting order.
	// Modules listed in DependsOn appear before the module that depends on them.
	// Returns an error if a dependency cycle is detected.
	StartupOrder() ([]string, error)

	// DependencyGraph returns modules that list the given ID in their DependsOn.
	// Useful for understanding the impact of stopping or removing a module.
	DependencyGraph(id string) ([]string, error)
}

Registry provides runtime discovery of registered modules.

type ResourceAuthorizer

type ResourceAuthorizer interface {
	Authorizer

	// CanWithResource performs a permission check with resource context.
	// The resource descriptor enables hierarchical checks, ABAC policies,
	// and resource-ownership gating. When ResourceDescriptor.ID is empty,
	// the check is scoped to the resource type.
	CanWithResource(ctx context.Context, session Session, action Action, resource ResourceDescriptor) (bool, error)
}

ResourceAuthorizer is an optional extension to Authorizer that enables resource-level permission checks with ABAC support. Implement this alongside Authorizer when your policy engine supports hierarchical resource permissions.

Callers that need resource-level authorization type-assert to this interface and fall back to Authorizer.Can() if not supported.

type ResourceDescriptor

type ResourceDescriptor struct {
	// Type is the resource kind, e.g. "media", "storage", "module".
	Type string
	// ID is the resource identifier, e.g. a UUID or key path.
	// Empty means the check is at the resource-type level.
	ID string
	// Attributes carries additional resource properties that
	// policy engines can use for ABAC decisions (owner, labels, tier).
	// MUST NOT contain credentials or PII.
	Attributes map[string]string
}

ResourceDescriptor carries the resource identifier and optional attributes for attribute-based access decisions.

type ResourcePublishPolicyProvider

type ResourcePublishPolicyProvider interface {
	PublishPolicyProvider

	// CanPublishEvent performs event-level authorization with access to
	// the full event payload. This enables resource-level checks beyond
	// the type-level check in CanPublish.
	CanPublishEvent(ctx context.Context, callerID string, event Event) (bool, error)
}

ResourcePublishPolicyProvider is an optional extension that enables resource-level event authorization with access to the full event payload. Implement this alongside PublishPolicyProvider to enable checks like "can this caller publish media.updated events for media item X?".

When a provider implements this interface, the event bus calls CanPublishEvent before CanPublish, giving the provider full event context.

type RetryPolicy

type RetryPolicy struct {
	// MaxAttempts is the maximum number of attempts, including the first.
	// A value of 0 means the provider's default (typically 3).
	MaxAttempts int

	// InitialDelay is the delay before the first retry.
	// A value of 0 means the provider's default (typically 100ms).
	InitialDelay time.Duration

	// MaxDelay is the maximum delay between retries. The backoff caps at this.
	// A value of 0 means no cap (provider default).
	MaxDelay time.Duration

	// BackoffFactor is multiplied against the delay on each retry.
	// Typical values: 2.0 (exponential), 1.0 (fixed delay).
	// A value of 0 means the provider's default (typically 2.0).
	BackoffFactor float64

	// Jitter, when true, adds random jitter to the delay to avoid thundering herd.
	Jitter bool

	// Extra carries provider-specific extensions.
	Extra map[string]any
}

RetryPolicy configures how a RetryProvider retries failed operations. Zero values mean "use the provider's default."

type RetryProvider

type RetryProvider interface {
	// Execute runs fn with retry semantics based on the given policy.
	// Returns nil if fn succeeds on any attempt. Returns the last error
	// if all attempts are exhausted. The context is passed to each attempt;
	// if ctx is cancelled, retries stop immediately.
	Execute(ctx context.Context, policy RetryPolicy, fn func(ctx context.Context) error) error
}

RetryProvider executes operations with configurable retry semantics. This contract is provider-agnostic: a module that wraps a call in RetryProvider.Execute works identically whether the backend uses simple backoff, exponential backoff with jitter, or a future retry strategy.

RetryProvider is complementary to CircuitBreaker. CircuitBreaker prevents cascading failures by opening the circuit when errors exceed a threshold. RetryProvider handles transient failures (network blips, temporary unavailability) by retrying individual calls with backoff. A robust module uses both.

If no RetryProvider is registered, Execute runs fn exactly once with no retries — modules don't need nil checks.

type Rows

type Rows interface {
	Next() bool
	Scan(dest ...any) error
	Close() error
}

Rows is an iterator over query result rows.

type Scheduler

type Scheduler interface {
	Schedule(ctx context.Context, task SchedulerTask) (string, error)
	Cancel(ctx context.Context, taskID string) error
	Status(ctx context.Context, taskID string) (SchedulerTaskStatus, error)
	// List returns all scheduled tasks matching the filter. Pass nil to list all.
	List(ctx context.Context, filter *SchedulerTaskFilter) ([]SchedulerTask, error)
}

Scheduler is implemented by scheduler modules (scheduler-cron, etc.) to provide task scheduling. Core defines the contract; modules provide the driver.

Discovered via FindByCapability(CapabilityScheduler).

type SchedulerTask

type SchedulerTask struct {
	ID       string
	Name     string
	CronExpr string
	Payload  []byte
	Timeout  time.Duration
	Meta     map[string]any
}

SchedulerTask is a unit of scheduled work. Payload carries the task data. Meta carries scheduler-specific or task-type-specific context that the scheduler module can interpret.

type SchedulerTaskFilter

type SchedulerTaskFilter struct {
	Status SchedulerTaskStatus
	Name   string // substring match on task name; empty matches all
}

SchedulerTaskFilter narrows List queries.

type SchedulerTaskStatus

type SchedulerTaskStatus string

SchedulerTaskStatus represents the lifecycle of a scheduled task.

const (
	SchedulerTaskScheduled SchedulerTaskStatus = "scheduled"
	SchedulerTaskRunning   SchedulerTaskStatus = "running"
	SchedulerTaskCompleted SchedulerTaskStatus = "completed"
	SchedulerTaskFailed    SchedulerTaskStatus = "failed"
	SchedulerTaskCancelled SchedulerTaskStatus = "cancelled"
)

type SecretsProvider

type SecretsProvider interface {
	// Get retrieves a secret by key. Returns an error if not found.
	Get(ctx context.Context, key string) (string, error)
	// Set stores a secret. Implementations may be read-only (e.g., env-backed)
	// and return an error for Set calls.
	Set(ctx context.Context, key, value string) error
	// Delete removes a secret. May not be supported by all backends.
	Delete(ctx context.Context, key string) error
	// List returns all known keys. Values are NOT included — only key names.
	List(ctx context.Context) ([]string, error)
}

SecretsProvider manages sensitive configuration values (API keys, tokens, passwords). Modules implement this to back secrets from environment variables, HashiCorp Vault, encrypted files, or external secret managers.

This contract exists so modules never read raw env vars for credentials. A module that needs a Jackett API key calls deps.Secrets.Get("jackett_api_key") instead of os.Getenv("JACKETT_API_KEY"). This enables audit logging, rotation, and centralized secret management without changing module code.

type Seekable

type Seekable interface {
	Seek(ctx context.Context, key string, offset int64) (int64, error)
}

type SerializationProvider

type SerializationProvider interface {
	// Marshal serializes v to bytes using the specified content type.
	// Common content types: "application/json", "application/x-protobuf",
	// "application/msgpack".
	Marshal(contentType string, v any) ([]byte, error)

	// Unmarshal deserializes data into v using the specified content type.
	// v must be a pointer to a concrete target type.
	//
	// SECURITY: The content type and data originate from untrusted sources
	// (the wire or another module). Implementations MUST validate the
	// content type against a safelist before deserializing.
	Unmarshal(contentType string, data []byte, v any) error

	// SupportedTypes returns the content types this provider can handle.
	// Callers can negotiate format by intersecting their needs with this list.
	//
	// SECURITY: The returned list MUST only include types that have been
	// vetted for safe deserialization. See SafeSerializationTypes above.
	SupportedTypes() []string
}

SerializationProvider handles marshaling and unmarshaling of data with content-type negotiation. Modules use this to serialize/deserialize payloads without knowing which format the other side expects.

A module producing protobuf can call Marshal("application/json", v) and the provider handles the conversion. A module consuming JSON can call Unmarshal(contentType, data, v) regardless of the wire format.

This contract is provider-agnostic: a module that calls Marshal/Unmarshal works identically whether the backend uses encoding/json + protobuf, msgpack, or a future serialization format.

SECURITY: Unmarshal deserializes untrusted data into an arbitrary target type. Implementations MUST:

  • Reject content types that support code execution (YAML v1, gob, etc.) unless sandboxed with strict decoding modes.
  • Enforce type safety — the target 'v' must be a concrete Go type, and the implementation must not instantiate types based on the serialized payload's type hints (no polymorphic deserialization).
  • Reject payloads that exceed a reasonable size limit to prevent memory-exhaustion DoS. A minimum of 10 MB per payload is recommended.

If no SerializationProvider is registered, modules handle serialization themselves — this is acceptable for simple deployments where all modules agree on a single format.

type Session

type Session struct {
	UserID      string
	Username    string
	Roles       []string
	Permissions []string
	Token       string // SECURITY: zero before logging or serializing
}

Session represents an authenticated session.

SECURITY WARNING: The Token field carries the raw bearer token. Session structs flow through the authorization path (Authorizer.Can), and can be inadvertently serialized in logs, audit entries, or event payloads. Consumers that pass Session to loggers or serializers MUST zero the Token field first. Use the Safe() method when passing session identity to non-security subsystems.

func (Session) Safe

func (s Session) Safe() Session

Safe returns a copy of the Session with the Token field zeroed. Use this when passing session information to subsystems that do not need the raw token (logging, metrics, events, workflows).

type SettingDef

type SettingDef struct {
	Key         string // env var or config key, e.g. "MUXCORE_JACKETT_URL"
	Label       string // human-readable label, e.g. "Jackett Server URL"
	Type        SettingType
	Default     string // default value as a string
	Description string // help text
	Required    bool
	Options     []string // for SettingTypeSelect: allowed values
	Group       string   // settings group, e.g. "Connection", "Downloads"
}

SettingDef describes one configuration setting that a module exposes.

type SettingType

type SettingType string

SettingType enumerates the supported setting types.

const (
	SettingTypeString SettingType = "string"
	SettingTypeInt    SettingType = "int"
	SettingTypeBool   SettingType = "bool"
	SettingTypeSelect SettingType = "select"
	SettingTypeSecret SettingType = "secret" // masked in UI, redacted in logs
)

type SettingsProvider

type SettingsProvider interface {
	Settings() []SettingDef
}

SettingsProvider is an optional interface modules implement to expose their configuration to the admin UI. The admin UI discovers all modules that implement this interface and renders their settings automatically.

type Span

type Span interface {
	// SetAttribute records a key-value pair on the span. Attributes appear
	// in trace visualizations and can be searched.
	SetAttribute(key string, value string)

	// SetStatus records the outcome of the span. Call before End().
	SetStatus(code SpanStatusCode, description string)

	// End marks the span as complete and sends it to the tracing backend.
	End()
}

Span represents a single unit of work in a distributed trace.

type SpanStatusCode

type SpanStatusCode int

SpanStatusCode indicates success or failure of a span.

const (
	SpanStatusOK    SpanStatusCode = 0
	SpanStatusError SpanStatusCode = 1
)

type SpoolResolver

type SpoolResolver interface {
	// ResolveTag fetches and parses a tag definition from the given spool URL.
	// The context carries deadlines and cancellation for the network request.
	ResolveTag(ctx context.Context, spoolURL, tagName string) (*TagDefinition, error)
}

SpoolResolver resolves a tag name into a list of module definitions from a spool URL. Implementations may support different spool formats (GitHub, self-hosted, IPFS, etc.).

Discovered via FindByCapability(CapabilitySpoolResolver). If no resolver is registered, core falls back to a generic HTTPS JSON fetcher.

type StepCompletedPayload

type StepCompletedPayload struct {
	RunID    string         `json:"run_id"`
	StepName string         `json:"step_name"`
	Duration string         `json:"duration"`
	Output   map[string]any `json:"output"`
}

type StepFailedPayload

type StepFailedPayload struct {
	RunID    string `json:"run_id"`
	StepName string `json:"step_name"`
	Attempt  int    `json:"attempt"`
	MaxRetry int    `json:"max_retry"`
	Error    string `json:"error"`
}

type StepHandler

type StepHandler struct {
	// Kind determines how Ref is interpreted.
	Kind StepHandlerKind
	// Ref is a module ID (Kind=StepHandlerModule) or capability string
	// (Kind=StepHandlerCapability).
	Ref string
}

StepHandler specifies which module handles a tapestry step. Exactly one of Kind+Ref must be set.

type StepHandlerKind

type StepHandlerKind string

StepHandlerKind identifies how a TapestryStep.Handler is resolved.

const (
	// StepHandlerModule routes the step to a specific module by ID.
	// Handler.Ref must be a module ID (e.g. "transcoder-ffmpeg").
	StepHandlerModule StepHandlerKind = "module"

	// StepHandlerCapability routes the step to any module advertising
	// the given capability. Handler.Ref must be a capability string
	// (e.g. "transcoder"). The workflow engine picks an available module.
	StepHandlerCapability StepHandlerKind = "capability"
)

type StepResult

type StepResult struct {
	StepName   string
	Status     string // "success", "failed", "skipped"
	StartedAt  time.Time
	EndedAt    time.Time
	Attempt    int
	MaxRetries int
	Output     map[string]any // step output data passed to subsequent steps
	Error      string
}

StepResult captures the outcome of one tapestry step.

type StepStartedPayload

type StepStartedPayload struct {
	RunID    string `json:"run_id"`
	StepName string `json:"step_name"`
	Handler  string `json:"handler"`
	Attempt  int    `json:"attempt"`
}

type StorageEvent

type StorageEvent struct {
	Type StorageEventType
	Key  string
}

type StorageEventType

type StorageEventType string
const (
	StorageEventCreated  StorageEventType = "created"
	StorageEventDeleted  StorageEventType = "deleted"
	StorageEventModified StorageEventType = "modified"
)

type StorageOrchestrator

type StorageOrchestrator interface {
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Put(ctx context.Context, key string, data io.Reader, size int64) error
	Delete(ctx context.Context, key string) error
	Move(ctx context.Context, src, dst string) error
	Exists(ctx context.Context, key string) (bool, error)
	Stat(ctx context.Context, key string) (ObjectInfo, error)
	List(ctx context.Context, prefix string) ([]ObjectInfo, error)
	// Stream reads a byte range from a storage object. Uses provider-side
	// streaming when the routed provider implements Streamable; otherwise
	// falls back to a full Get with client-side slicing.
	Stream(ctx context.Context, key string, offset, length int64) (io.ReadCloser, error)
	// CapabilityCheck returns which capability interfaces the routed provider
	// supports for the given key (streamable, seekable, watchable, etc.).
	// Modules use this to negotiate behavior at runtime.
	CapabilityCheck(ctx context.Context, key string) ([]string, error)
}

StorageOrchestrator is the high-level storage interface exposed to modules. It handles provider routing, caching, and capability negotiation internally.

type StorageProvider

type StorageProvider interface {
	Put(ctx context.Context, key string, data io.Reader, size int64) error
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Delete(ctx context.Context, key string) error
	Move(ctx context.Context, src, dst string) error
	Exists(ctx context.Context, key string) (bool, error)
	Stat(ctx context.Context, key string) (ObjectInfo, error)
	List(ctx context.Context, prefix string) ([]ObjectInfo, error)
}

Core blob storage interface — all storage providers implement this.

type StorageTier

type StorageTier string

StorageTier represents the performance/cost tier of a storage backend.

const (
	StorageTierHot     StorageTier = "hot"
	StorageTierWarm    StorageTier = "warm"
	StorageTierCold    StorageTier = "cold"
	StorageTierArchive StorageTier = "archive"
)

type Streamable

type Streamable interface {
	Stream(ctx context.Context, key string, offset, length int64) (io.ReadCloser, error)
}

type StructuredLogger

type StructuredLogger interface {
	// Debug logs at debug level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Debug(ctx context.Context, msg string, fields map[string]any)

	// Info logs at info level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Info(ctx context.Context, msg string, fields map[string]any)

	// Warn logs at warning level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Warn(ctx context.Context, msg string, fields map[string]any)

	// Error logs at error level with structured fields.
	// SECURITY: fields may contain sensitive data — redact before calling.
	Error(ctx context.Context, msg string, fields map[string]any)

	// Level returns the configured minimum log level. Messages below this
	// level are silently dropped by the provider.
	Level() LogLevel
}

StructuredLogger provides leveled, structured logging for modules. This is the general-purpose logger — distinct from AuditLogger which handles security-relevant audit events specifically.

Modules call StructuredLogger instead of importing a specific logging library. This makes the logging backend swappable (slog, zap, zerolog, or a future standard) without changing module code.

SECURITY: All log methods accept fields as map[string]any. This map can inadvertently contain credentials, tokens, PII, or other sensitive data. Callers MUST:

  • Apply DataRedactionProvider.Redact() to the fields map before passing it to any log method if the map contains untrusted data.
  • Never log full Identity structs — use Identity.SafeInfo().
  • Never log Session structs — use Session.Safe().
  • Avoid logging raw request bodies, query parameters, or headers.

Implementations SHOULD apply automatic field-name-based redaction for keys matching SensitiveLogFieldNames before writing to any sink.

If no StructuredLogger is registered, log calls are no-ops — modules do not need nil checks.

type TagDefinition

type TagDefinition struct {
	Name        string      `json:"name"`
	Description string      `json:"description"`
	Version     string      `json:"version"`
	Modules     []TagModule `json:"modules"`
}

TagDefinition is a curated module preset fetched from a spool.

type TagModule

type TagModule struct {
	Repo     string `json:"repo"`
	Version  string `json:"version"`
	Required bool   `json:"required"`
	Checksum string `json:"checksum,omitempty"`
	// InstanceID differentiates multiple copies of the same module on one
	// node. When set, the derived module ID becomes "{baseID}-{instanceID}"
	// instead of just "{baseID}". Allows running two identical modules
	// with different config (e.g. two torrent downloaders on different ports).
	InstanceID string `json:"instance_id,omitempty"`
	// Config is instance-specific configuration passed as environment
	// variables to the module binary. Each key is prefixed with MUXCORE_CFG_
	// and set as an env var during spawn.
	Config map[string]string `json:"config,omitempty"`
}

TagModule is a single module entry in a spool tag definition.

type TapestryCompletedPayload

type TapestryCompletedPayload struct {
	RunID        string `json:"run_id"`
	DefinitionID string `json:"definition_id"`
	Duration     string `json:"duration"`
}

type TapestryDefinition

type TapestryDefinition struct {
	ID          string
	Name        string
	Description string
	Steps       []TapestryStep
	Version     string
	Meta        map[string]any
}

TapestryDefinition is a registered, reusable workflow template.

type TapestryFailedPayload

type TapestryFailedPayload struct {
	RunID        string `json:"run_id"`
	DefinitionID string `json:"definition_id"`
	StepName     string `json:"step_name"`
	Error        string `json:"error"`
}

type TapestryRun

type TapestryRun struct {
	ID           string
	DefinitionID string
	Status       TapestryStatus
	CurrentStep  string
	StepResults  []StepResult
	Input        map[string]any
	StartedAt    time.Time
	EndedAt      time.Time
	Error        string
	Meta         map[string]any
}

TapestryRun represents a single execution of a tapestry.

type TapestryRunFilter

type TapestryRunFilter struct {
	Status       TapestryStatus
	DefinitionID string
}

TapestryRunFilter narrows ListRuns queries.

type TapestryStartedPayload

type TapestryStartedPayload struct {
	RunID        string `json:"run_id"`
	DefinitionID string `json:"definition_id"`
}

Tapestry event payloads.

type TapestryStatus

type TapestryStatus string

TapestryStatus tracks the lifecycle of a running workflow.

const (
	TapestryPending   TapestryStatus = "pending"
	TapestryRunning   TapestryStatus = "running"
	TapestryCompleted TapestryStatus = "completed"
	TapestryFailed    TapestryStatus = "failed"
	TapestryCancelled TapestryStatus = "cancelled"
	TapestryPaused    TapestryStatus = "paused"
)

type TapestryStep

type TapestryStep struct {
	Name         string
	Handler      StepHandler
	Retry        int // max retry attempts (0 = no retry)
	Timeout      time.Duration
	DependsOn    []string          // step names that must complete before this one
	InputMapping map[string]string // maps step output keys to this step's input keys
	Meta         map[string]any
}

TapestryStep defines one step in a tapestry definition.

type TierTransitionPayload

type TierTransitionPayload struct {
	Key      string      `json:"key"`
	FromTier StorageTier `json:"from_tier"`
	ToTier   StorageTier `json:"to_tier"`
	Reason   string      `json:"reason"`
}

TierTransitionPayload is the payload for storage.tier.transition events. Experimental — may change before the first tiered storage module ships.

type TieredProvider

type TieredProvider interface {
	StorageProvider

	// Tier returns which tier this provider handles.
	Tier() StorageTier

	// Promote moves an object from this tier to a higher one.
	Promote(ctx context.Context, key string) error

	// Relegate moves an object from this tier to a lower one.
	Relegate(ctx context.Context, key string) error
}

TieredProvider extends StorageProvider with tiering support. Storage modules that support multiple tiers implement this.

type TracingProvider

type TracingProvider interface {
	// StartSpan begins a new span with the given name as a child of any
	// span in ctx. Returns the context carrying the new span and the span
	// itself. Call span.End() when the operation completes.
	StartSpan(ctx context.Context, name string) (context.Context, Span)
}

TracingProvider creates spans for distributed tracing. Modules call this to wrap operations in spans; the provider handles export to whatever backend is configured (Jaeger, Zipkin, OTLP, or future protocols).

If no TracingProvider is registered, StartSpan returns the context unchanged and a no-op span — modules don't need nil checks.

This contract is provider-agnostic by design. A module that creates spans through TracingProvider works identically whether the backend is OpenTelemetry, a proprietary APM, or a future standard.

type Tx

type Tx interface {
	// SECURITY: Same SQL parameterization requirements as DatabaseProvider.Exec/Query.
	Exec(ctx context.Context, query string, args ...any) (int64, error)
	Query(ctx context.Context, query string, args ...any) (Rows, error)
}

Tx is a database transaction handle.

type ValidationResult

type ValidationResult struct {
	// Valid is true if the input passed all schema checks without errors.
	// When Valid is true, Sanitized holds the (possibly cleaned) data
	// that should be used in place of the original.
	Valid bool

	// Sanitized is the cleaned/sanitized version of the input data.
	// When Valid is true, callers should use this instead of the raw input.
	// When Valid is false, Sanitized may be nil or partial.
	Sanitized []byte

	// Errors is the list of validation failures. Empty when Valid is true.
	// Each entry describes a specific failure (e.g., "field email must
	// match pattern ^[^@]+@[^@]+$").
	Errors []string
}

ValidationResult carries the outcome of an input validation call. Modules use this to decide whether to accept, reject, or sanitize incoming data before processing.

type Watchable

type Watchable interface {
	Watch(ctx context.Context, prefix string) (<-chan StorageEvent, error)
}

type WorkerPool

type WorkerPool interface {
	Submit(ctx context.Context, task WorkerTask) (string, error)
	Status(ctx context.Context, taskID string) (WorkerTask, error)
	Cancel(ctx context.Context, taskID string) error
	List(ctx context.Context, filter *WorkerTaskFilter) ([]WorkerTask, error)

	// Reassign moves a task from a dead or unresponsive node to a new one.
	// If the task is already completed or cancelled, Reassign returns an error.
	// The new node should re-execute the task from scratch unless the executor
	// checks IdempotencyKey against an IdempotencyProvider.
	Reassign(ctx context.Context, taskID, newNode string) error
}

WorkerPool schedules tasks across cluster nodes and tracks their lifecycle.

type WorkerTask

type WorkerTask struct {
	ID            string
	Type          string
	Payload       []byte
	AssignedNode  string
	Status        WorkerTaskStatus
	MaxRetries    int
	RetryCount    int
	Capabilities  []string
	CreatedAt     time.Time
	StartedAt     time.Time
	CompletedAt   time.Time
	LastHeartbeat time.Time
	Error         string
	Meta          map[string]any

	// IdempotencyKey is an optional key that executors use with
	// IdempotencyProvider to prevent duplicate execution. When a task
	// is reassigned after a node failure, the new executor checks this
	// key before re-executing. If empty, no idempotency guard is applied.
	IdempotencyKey string

	// HeartbeatInterval is how often the executor promises to call
	// Heartbeat() while processing this task. The worker pool reaper
	// uses this to detect stalled executors. If zero, the pool's
	// DefaultHeartbeatTimeout is used.
	HeartbeatInterval time.Duration
}

WorkerTask is a unit of work scheduled across the cluster. Meta carries task-type-specific context that executors interpret.

type WorkerTaskFilter

type WorkerTaskFilter struct {
	Status       WorkerTaskStatus
	Type         string
	AssignedNode string
}

WorkerTaskFilter narrows task queries.

type WorkerTaskStatus

type WorkerTaskStatus string

WorkerTaskStatus represents the lifecycle of a distributed task.

const (
	WorkerTaskStatusPending   WorkerTaskStatus = "pending"
	WorkerTaskStatusAssigned  WorkerTaskStatus = "assigned"
	WorkerTaskStatusRunning   WorkerTaskStatus = "running"
	WorkerTaskStatusCompleted WorkerTaskStatus = "completed"
	WorkerTaskStatusFailed    WorkerTaskStatus = "failed"
	WorkerTaskStatusCancelled WorkerTaskStatus = "cancelled"
)

type WorkflowEngine

type WorkflowEngine interface {
	// RegisterDefinition stores a tapestry template for later execution.
	// definition.ID is the key used by Run.
	RegisterDefinition(ctx context.Context, definition TapestryDefinition) error

	// RemoveDefinition removes a previously registered definition.
	RemoveDefinition(ctx context.Context, definitionID string) error

	// GetDefinition returns a registered definition, or nil if not found.
	GetDefinition(ctx context.Context, definitionID string) (*TapestryDefinition, error)

	// ListDefinitions returns all registered definitions.
	ListDefinitions(ctx context.Context) ([]TapestryDefinition, error)

	// Run starts a tapestry execution. input carries the initial
	// data passed to the first step(s).
	Run(ctx context.Context, definitionID string, input map[string]any) (string, error)

	// Status returns the current state of a run.
	Status(ctx context.Context, runID string) (*TapestryRun, error)

	// Cancel stops a running tapestry. Already-completed steps
	// are not rolled back.
	Cancel(ctx context.Context, runID string) error

	// Pause suspends a running tapestry at the next step boundary.
	Pause(ctx context.Context, runID string) error

	// Resume continues a paused tapestry.
	Resume(ctx context.Context, runID string) error

	// ListRuns returns all runs, optionally filtered by status or definitionID.
	ListRuns(ctx context.Context, filter *TapestryRunFilter) ([]TapestryRun, error)
}

WorkflowEngine orchestrates multi-step tapestry executions. Discovered via FindByCapability(CapabilityWorkflowEngine). If no module implements this contract, individual Scheduler tasks can still run independently — tapestry execution is an optional layer.

Jump to

Keyboard shortcuts

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