models

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 7, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DatasetDirectionProduces = "produces"
	DatasetDirectionConsumes = "consumes"
	DatasetDirectionSource   = "source"
)

Dataset declaration direction values. They mirror the jobdef constants (pkg/jobdef.DatasetDirection*) and are duplicated here so the models package stays free of a jobdef import.

View Source
const (
	DatasetDecisionDerived          = "derived"
	DatasetDecisionSkippedFresh     = "skipped_fresh"
	DatasetDecisionSkippedUpstream  = "skipped_upstream"
	DatasetDecisionSkippedAdmission = "skipped_admission"
	DatasetDecisionSkippedActiveRun = "skipped_active_run"
)

Dataset derivation decision values — the "why did/didn't this run" audit the leader-gated evaluator (Stream C) appends. A `derived` decision carries the resulting run id; the `skipped_*` decisions record why no run was started.

View Source
const (
	DatasetStatusUnknown       = "unknown"
	DatasetStatusFresh         = "fresh"
	DatasetStatusStale         = "stale"
	DatasetStatusStaleUpstream = "stale-upstream"
	DatasetStatusViolated      = "violated"
	DatasetStatusQuarantined   = "quarantined"
)

Dataset freshness status values. The state store (internal/freshness) sets a neutral default; the leader-gated evaluator (Stream C) owns the transitions between fresh/stale/stale-upstream/violated/quarantined.

View Source
const (
	JobRunStatusCancelled  = "cancelled"
	TaskRunStatusCancelled = "cancelled"
)
View Source
const DefaultTriageOnlyProfileName = "triage-only"

DefaultTriageOnlyProfileName is the shipped zero-risk default AgentProfile: tier 0 (deterministic rules only) plus escalate, so teams can adopt agent-in-the-loop remediation incrementally without granting any autonomous action. It is a built-in name: a job's metadata.remediation.profile may reference it and server-side lint/apply treats it as always resolvable even before the row is seeded, so a fresh server never rejects the advertised default. See docs/design-agent-in-the-loop.md.

View Source
const ExecutionEventTypeRunCancelled = "run_cancelled"
View Source
const TaskExecutionDescriptorSchemaVersion = 1

Variables

All lists every model for AutoMigrate. Order matters: parent tables must appear before children so that foreign-key constraints can reference them.

Functions

func NormalizedTriggerPath

func NormalizedTriggerPath(path string) string

func NormalizedTriggerPathForConfiguration

func NormalizedTriggerPathForConfiguration(triggerType TriggerType, configuration string) (string, error)

func RoleLevel

func RoleLevel(r Role) int

RoleLevel returns the numeric privilege level for a role. Higher values indicate more privileges.

func ValidRole

func ValidRole(r string) bool

ValidRole returns true if r is a recognised role string.

Types

type APIKey

type APIKey struct {
	ID            uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	KeyPrefix     string         `gorm:"type:text;size:12;not null;index" json:"key_prefix"`
	KeyHash       string         `gorm:"type:text;not null;uniqueIndex" json:"-"`
	BootstrapSlot *string        `gorm:"type:text;uniqueIndex" json:"-"`
	Description   string         `gorm:"type:text" json:"description,omitempty"`
	Role          Role           `gorm:"type:text;not null" json:"role"`
	Scope         datatypes.JSON `gorm:"type:json" json:"scope,omitempty"`
	CreatedBy     string         `gorm:"type:text" json:"created_by,omitempty"`
	CreatedAt     time.Time      `gorm:"not null" json:"created_at"`
	ExpiresAt     *time.Time     `json:"expires_at,omitempty"`
	LastUsedAt    *time.Time     `json:"last_used_at,omitempty"`
	RevokedAt     *time.Time     `json:"revoked_at,omitempty"`
}

APIKey represents an API key stored in the database. The plaintext key is never persisted — only a versioned stored hash.

func (*APIKey) IsExpired

func (k *APIKey) IsExpired() bool

IsExpired returns true when the key has passed its expiration time.

func (*APIKey) IsRevoked

func (k *APIKey) IsRevoked() bool

IsRevoked returns true when the key has been revoked.

type AgentAction

type AgentAction struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
	// Namespace is nullable from day one (design Open Question 4).
	Namespace *string `gorm:"type:text;index" json:"namespace,omitempty"`

	// IncidentID is non-nullable — the audit spine always ties to an incident.
	IncidentID uuid.UUID `gorm:"type:uuid;index;not null" json:"incident_id"`
	Incident   Incident  `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	// SessionID is nullable: policy/human rows have no agent session.
	SessionID *uuid.UUID    `gorm:"type:uuid;index" json:"session_id,omitempty"`
	Session   *AgentSession `gorm:"constraint:OnDelete:SET NULL" json:"-"`

	Type   string            `gorm:"type:text;index;not null" json:"type"`
	Params datatypes.JSON    `gorm:"type:json" json:"params,omitempty"`
	Tier   int               `gorm:"not null;default:0" json:"tier"`
	Status AgentActionStatus `gorm:"type:text;index;not null" json:"status"`
	Result datatypes.JSON    `gorm:"type:json" json:"result,omitempty"`
	Actor  AgentActionActor  `gorm:"type:text;index;not null" json:"actor"`

	CreatedAt time.Time `gorm:"not null;index" json:"created_at"`
	UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
}

AgentAction is the audit spine: every remediation attempt (whether taken by a deterministic policy rule, the container agent, or a human) is recorded as a row. The incident reference is NON-NULLABLE so the timeline reconstructs for actor=policy|human rows that have no session; the session reference is nullable. Append-only, low-volume.

type AgentActionActor

type AgentActionActor string

AgentActionActor identifies who originated an action row.

const (
	// ActorPolicy is a deterministic server-side rule (Phase 0) — no container.
	AgentActionActorPolicy AgentActionActor = "policy"
	// ActorAgent is the container-native agent (Phase 1+).
	AgentActionActorAgent AgentActionActor = "agent"
	// ActorHuman is an operator action.
	AgentActionActorHuman AgentActionActor = "human"
)

type AgentActionStatus

type AgentActionStatus string

AgentActionStatus enumerates an action's lifecycle in the audit spine.

const (
	AgentActionStatusProposed AgentActionStatus = "proposed"
	AgentActionStatusApproved AgentActionStatus = "approved"
	AgentActionStatusRejected AgentActionStatus = "rejected"
	// AgentActionStatusExecuting is the CLAIM an approved action holds while it
	// is being dispatched. It exists so dispatch is once-only: the executor moves
	// approved → executing with a conditional UPDATE, and a second attempt (the
	// redrive sweeper racing the synchronous post-decision execute, or two
	// operators' requests interleaving) matches zero rows and does nothing.
	//
	// A row left `executing` by a process death is a deliberately VISIBLE stuck
	// state, not an invisible one: it is never auto-redriven, because re-running a
	// half-applied tier-3 mutation (a jobdef patch, a skipped task) unattended is
	// worse than surfacing it for a human. See ApprovalRedriver.
	AgentActionStatusExecuting AgentActionStatus = "executing"
	AgentActionStatusExecuted  AgentActionStatus = "executed"
	AgentActionStatusFailed    AgentActionStatus = "failed"
)

type AgentClaim

type AgentClaim struct {
	// IncidentID is the only incident whose /v1/agent/* routes this key may call.
	IncidentID uuid.UUID `json:"incident_id"`
	// Jobs is the frozen job allowlist governing which jobs' read-only context
	// (logs, why, run history) the agent may pull through the context routes.
	Jobs []string `json:"jobs,omitempty"`
}

AgentClaim binds an API key to a single incident's agent tool surface. It is minted by the incident manager (an unscoped, server-side principal) for one agent session and expires with that session. The read scope is FROZEN at incident open: Jobs is the static job allowlist the incident manager snapshotted from the lineage-impact graph (excluding edges derived from the failing run's own outputs). The agent cannot widen it — server-side enforcement is the boundary, not the prompt.

type AgentProfile

type AgentProfile struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
	// Namespace is nullable from day one (design Open Question 4).
	Namespace *string `gorm:"type:text;index" json:"namespace,omitempty"`

	Name   string     `gorm:"uniqueIndex;not null" json:"name"`
	Image  string     `gorm:"type:text;not null" json:"image"`
	Engine AtomEngine `gorm:"type:text;not null;default:'docker'" json:"engine"`

	// Limits holds resource limits (cpu/memory/wall-clock) as JSON.
	Limits datatypes.JSON `gorm:"type:json" json:"limits,omitempty"`
	// SecretRefs holds secret:// references (e.g. the model API key) as JSON.
	// Never resolved values — only the references.
	SecretRefs datatypes.JSON `gorm:"type:json" json:"secret_refs,omitempty"`
	// Budgets holds per-session budget defaults (max actions, token/cost caps).
	Budgets datatypes.JSON `gorm:"type:json" json:"budgets,omitempty"`
	// Playbook holds the default action-catalog policy for jobs using this profile.
	Playbook datatypes.JSON `gorm:"type:json" json:"playbook,omitempty"`

	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt time.Time      `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time      `gorm:"not null" json:"updated_at"`
}

AgentProfile is the server-side resource declaring how a remediation agent runs: its container image/engine, resource limits, model-credential secret:// references, session budgets, and the default playbook. It is referenced by a job's metadata.remediation block. Low-volume catalog row.

type AgentSession

type AgentSession struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
	// Namespace is nullable from day one (design Open Question 4).
	Namespace *string `gorm:"type:text;index" json:"namespace,omitempty"`

	IncidentID uuid.UUID `gorm:"type:uuid;index;not null" json:"incident_id"`
	Incident   Incident  `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	ProfileID *uuid.UUID    `gorm:"type:uuid;index" json:"profile_id,omitempty"`
	Profile   *AgentProfile `gorm:"constraint:OnDelete:SET NULL" json:"-"`

	Engine AtomEngine `gorm:"type:text" json:"engine,omitempty"`
	// AtomID / ContainerID identify the launched container/atom for the UI and
	// for stop/cleanup.
	AtomID      *uuid.UUID `gorm:"type:uuid;index" json:"atom_id,omitempty"`
	ContainerID string     `gorm:"type:text" json:"container_id,omitempty"`

	// TokenID is the scoped, short-lived agent credential bound to this session.
	TokenID *uuid.UUID `gorm:"type:uuid;index" json:"token_id,omitempty"`

	State AgentSessionState `gorm:"type:text;index;not null;default:'pending'" json:"state"`
	// SessionLog is the persisted agent-container log for the UI timeline.
	SessionLog string `gorm:"type:text" json:"session_log,omitempty"`

	// Budget counters. These are best-effort accounting the executor increments.
	ActionsUsed int `gorm:"not null;default:0" json:"actions_used"`
	TokensUsed  int `gorm:"not null;default:0" json:"tokens_used"`

	StartedAt   *time.Time `json:"started_at,omitempty"`
	CompletedAt *time.Time `json:"completed_at,omitempty"`
	CreatedAt   time.Time  `gorm:"not null" json:"created_at"`
	UpdatedAt   time.Time  `gorm:"not null" json:"updated_at"`
	// Extra carries additional session metadata (e.g. frozen allowlist) as JSON.
	Extra datatypes.JSON `gorm:"type:json" json:"extra,omitempty"`
}

AgentSession records a single agent container run launched through the existing atom.Engine to triage an incident. It is DELIBERATELY NOT a JobRun / TaskRun: a session materialized as a run would pollute the quarantine-filtered run statistics and feed its own exhaust back into the incident bus. Low-volume.

type AgentSessionState

type AgentSessionState string

AgentSessionState enumerates the terminal-tracked lifecycle of an agent container session.

const (
	AgentSessionStatePending   AgentSessionState = "pending"
	AgentSessionStateRunning   AgentSessionState = "running"
	AgentSessionStateSucceeded AgentSessionState = "succeeded"
	AgentSessionStateFailed    AgentSessionState = "failed"
	AgentSessionStateTimedOut  AgentSessionState = "timed_out"
	AgentSessionStateCancelled AgentSessionState = "cancelled"
)

type ApprovalDecision

type ApprovalDecision string

ApprovalDecision enumerates the outcome of a tier-3 approval request.

const (
	ApprovalDecisionPending  ApprovalDecision = "pending"
	ApprovalDecisionApproved ApprovalDecision = "approved"
	ApprovalDecisionRejected ApprovalDecision = "rejected"
	ApprovalDecisionExpired  ApprovalDecision = "expired"
)

type ApprovalRequest

type ApprovalRequest struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
	// Namespace is nullable from day one (design Open Question 4).
	Namespace *string `gorm:"type:text;index" json:"namespace,omitempty"`

	// IncidentID lets the operator read API filter approvals by incident without
	// a join through the action.
	IncidentID uuid.UUID `gorm:"type:uuid;index;not null" json:"incident_id"`

	ActionID uuid.UUID   `gorm:"type:uuid;index;not null" json:"action_id"`
	Action   AgentAction `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	// ApproversHint is a free-text hint for who should decide (role/channel).
	ApproversHint string           `gorm:"type:text" json:"approvers_hint,omitempty"`
	Decision      ApprovalDecision `gorm:"type:text;index;not null;default:'pending'" json:"decision"`
	// Decider records the operator identity that resolved the request.
	Decider string `gorm:"type:text" json:"decider,omitempty"`
	Reason  string `gorm:"type:text" json:"reason,omitempty"`

	ExpiresAt *time.Time `gorm:"index" json:"expires_at,omitempty"`
	DecidedAt *time.Time `json:"decided_at,omitempty"`
	CreatedAt time.Time  `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time  `gorm:"not null" json:"updated_at"`
}

ApprovalRequest is created by every tier-3 action and resolved by a human operator. Tier-3 actions are NEVER auto-executed regardless of config, so an approval always terminates at a human decision. Low-volume catalog row.

type Atom

type Atom struct {
	ID                 uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Engine             AtomEngine     `gorm:"index;not null" json:"engine"`
	Image              string         `gorm:"index;not null" json:"image"`
	Command            string         `gorm:"command" json:"command"`
	Spec               datatypes.JSON `gorm:"type:jsonb" json:"spec"`
	ReplaySafe         bool           `gorm:"not null;default:false" json:"replay_safe"`
	ProvenanceSourceID string         `gorm:"index" json:"provenance_source_id"`
	ProvenanceRepo     string         `json:"provenance_repo"`
	ProvenanceRef      string         `json:"provenance_ref"`
	ProvenanceCommit   string         `json:"provenance_commit"`
	ProvenancePath     string         `json:"provenance_path"`
	DeletedAt          gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt          time.Time      `gorm:"not null" json:"created_at"`
	UpdatedAt          time.Time      `gorm:"not null" json:"updated_at"`
}

func (*Atom) Cmd

func (a *Atom) Cmd() []string

func (*Atom) ContainerSpec

func (a *Atom) ContainerSpec() container.Spec

type AtomEngine

type AtomEngine string
const (
	AtomEngineDocker     AtomEngine = "docker"
	AtomEngineKubernetes AtomEngine = "kubernetes"
	AtomEnginePodman     AtomEngine = "podman"
)

type Atoms

type Atoms []*Atom

type AuditLog

type AuditLog struct {
	ID           uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Timestamp    time.Time      `gorm:"not null;index" json:"timestamp"`
	Actor        string         `gorm:"type:text;not null;index" json:"actor"`
	Action       string         `gorm:"type:text;not null;index" json:"action"`
	ResourceType string         `gorm:"type:text" json:"resource_type,omitempty"`
	ResourceID   string         `gorm:"type:text" json:"resource_id,omitempty"`
	SourceIP     string         `gorm:"type:text" json:"source_ip,omitempty"`
	Outcome      string         `gorm:"type:text;not null" json:"outcome"`
	Metadata     datatypes.JSON `gorm:"type:json" json:"metadata,omitempty"`
}

AuditLog records every state-changing operation and auth rejection.

type Backfill

type Backfill struct {
	ID                uuid.UUID  `gorm:"type:uuid;primaryKey" json:"id"`
	JobID             uuid.UUID  `gorm:"type:uuid;index;not null" json:"job_id"`
	Job               Job        `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	Status            string     `gorm:"type:text;not null" json:"status"`
	Start             time.Time  `gorm:"not null" json:"start"`
	End               time.Time  `gorm:"not null" json:"end"`
	MaxConcurrent     int        `gorm:"not null;default:1" json:"max_concurrent"`
	Reprocess         string     `gorm:"type:text;not null" json:"reprocess"`
	TotalRuns         int        `gorm:"not null;default:0" json:"total_runs"`
	CompletedRuns     int        `gorm:"not null;default:0" json:"completed_runs"`
	FailedRuns        int        `gorm:"not null;default:0" json:"failed_runs"`
	CancelRequestedAt *time.Time `json:"cancel_requested_at,omitempty"`
	CompletedAt       *time.Time `json:"completed_at,omitempty"`
	CreatedAt         time.Time  `gorm:"not null" json:"created_at"`
	UpdatedAt         time.Time  `gorm:"not null" json:"updated_at"`
}

type BackfillStatus

type BackfillStatus string
const (
	BackfillStatusRunning   BackfillStatus = "running"
	BackfillStatusSucceeded BackfillStatus = "succeeded"
	BackfillStatusFailed    BackfillStatus = "failed"
	BackfillStatusCancelled BackfillStatus = "cancelled"
)

type Callback

type Callback struct {
	ID            uuid.UUID      `gorm:"type:uuid;primaryKey"`
	Type          CallbackType   `gorm:"index;type:string;not null"`
	Configuration string         `gorm:"not null"`
	JobID         uuid.UUID      `gorm:"index;not null"`
	Job           Job            `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	Position      int            `gorm:"not null;default:0" json:"-"`
	DeletedAt     gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt     time.Time      `gorm:"not null"`
	UpdatedAt     time.Time      `gorm:"not null"`
}

type CallbackRun

type CallbackRun struct {
	ID          uuid.UUID         `gorm:"type:uuid;primaryKey"`
	CallbackID  uuid.UUID         `gorm:"type:uuid;index;not null"`
	Callback    Callback          `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	JobID       uuid.UUID         `gorm:"type:uuid;index;not null"`
	JobRunID    uuid.UUID         `gorm:"type:uuid;index;not null"`
	JobRun      JobRun            `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	Status      CallbackRunStatus `gorm:"type:text;index;not null"`
	Error       string            `gorm:"type:text"`
	StartedAt   time.Time         `gorm:"not null"`
	CompletedAt *time.Time
	CreatedAt   time.Time `gorm:"not null"`
	UpdatedAt   time.Time `gorm:"not null"`
}

type CallbackRunStatus

type CallbackRunStatus string
const (
	CallbackRunStatusPending   CallbackRunStatus = "pending"
	CallbackRunStatusRunning   CallbackRunStatus = "running"
	CallbackRunStatusSucceeded CallbackRunStatus = "succeeded"
	CallbackRunStatusFailed    CallbackRunStatus = "failed"
)

type CallbackRuns

type CallbackRuns []*CallbackRun

type CallbackType

type CallbackType string
const (
	CallbackTypeNotification CallbackType = "notification"
)

type Callbacks

type Callbacks []*Callback

type ChannelType

type ChannelType string

ChannelType identifies the notification transport.

const (
	ChannelTypeWebhook   ChannelType = "webhook"
	ChannelTypeSlack     ChannelType = "slack"
	ChannelTypeEmail     ChannelType = "email"
	ChannelTypePagerDuty ChannelType = "pagerduty"
	ChannelTypeAIAgent   ChannelType = "ai_agent"
)

type ContractAck

type ContractAck struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`

	// Dataset is the human-readable contract subject: an OpenLineage dataset
	// identity when present, otherwise the producer output-key subject for an
	// inferred event-trigger edge.
	Dataset string `gorm:"type:text;not null;index:idx_contract_ack_dataset_digest,priority:1" json:"dataset"`
	// EdgeSetDigest is a deterministic digest over the breaking edge set the
	// ack covers. C2's --allow-breaking path writes this exact value.
	EdgeSetDigest string `gorm:"type:text;not null;index:idx_contract_ack_dataset_digest,priority:2;index" json:"edge_set_digest"`

	Actor  string `gorm:"type:text;not null;default:''" json:"actor"`
	Reason string `gorm:"type:text;not null;default:''" json:"reason"`

	CreatedAt time.Time `gorm:"not null" json:"created_at"`
	ExpiresAt time.Time `gorm:"not null;index" json:"expires_at"`
}

ContractAck records an intentional, time-bounded acknowledgement of a breaking contract edge set. It is a low-volume catalog table; run hot paths must not depend on it.

type DagSnapshot

type DagSnapshot struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`

	// JobID links this snapshot to its job. Rows are cascade-deleted when the
	// job is hard-deleted; soft-deleted jobs retain their snapshots.
	// Part of the composite dedup index (job_id, content_hash) and the
	// query-by-recency index (job_id, created_at).
	JobID uuid.UUID `gorm:"type:uuid;not null;index:idx_dag_snapshot_job_hash;index:idx_dag_snapshot_job_created" json:"job_id"`
	Job   Job       `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	// ContentHash is a SHA-256 hex digest of the canonical topology (sorted
	// task names each with image+command, plus sorted from→to edge pairs).
	// It is the dedup key: if the most-recent snapshot for this job already
	// carries this hash, no new row is written.
	ContentHash string `gorm:"type:text;not null;index:idx_dag_snapshot_job_hash" json:"content_hash"`

	// GitCommit is the provenance commit SHA at apply time (empty when the
	// apply carries no provenance). Together with ContentHash it lets callers
	// identify "when did this topology first appear and from which commit."
	GitCommit string `gorm:"type:text;not null;default:''" json:"git_commit"`

	// Tasks is a JSON array of task descriptors (name, image, command) captured
	// at snapshot time. It is informational — the live task_runs rows remain
	// authoritative for execution.
	Tasks datatypes.JSON `gorm:"type:json;not null" json:"tasks"`

	// Edges is a JSON array of edge descriptors ({from, to, provenance_commit})
	// captured at snapshot time.
	Edges datatypes.JSON `gorm:"type:json;not null" json:"edges"`

	// CreatedAt is the wall-clock time the snapshot was written (append-only;
	// rows are never updated). Part of the idx_dag_snapshot_job_created index
	// so the dedup query (ORDER BY created_at DESC LIMIT 1) uses the index.
	CreatedAt time.Time `gorm:"not null;index:idx_dag_snapshot_job_created" json:"created_at"`
}

DagSnapshot is an append-only record of a job's full topology (tasks + edges) at a point in time. One row is written per apply when the topology changes; unchanged topology reuses the existing row (dedup by ContentHash).

This is the persistence layer for Component 3 (Version DAG topology) from docs/design-data-plane-memory.md. The live graph in task_edges still drives execution; dag_snapshots preserves history so "the pipeline as of commit X" is reconstructable from dqlite without a git checkout.

type DagSnapshotEdge

type DagSnapshotEdge struct {
	From             string `json:"from"`
	To               string `json:"to"`
	ProvenanceCommit string `json:"provenance_commit,omitempty"`
}

DagSnapshotEdge is the per-edge descriptor stored inside DagSnapshot.Edges.

type DagSnapshotTask

type DagSnapshotTask struct {
	Name    string   `json:"name"`
	Image   string   `json:"image"`
	Command []string `json:"command,omitempty"`
}

DagSnapshotTask is the per-task descriptor stored inside DagSnapshot.Tasks. Command is stored as a slice (not space-joined) to preserve argument boundaries.

type DatasetDeclaration

type DatasetDeclaration struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`

	// JobID links this declaration to its job. Rows are cascade-deleted when the
	// job is hard-deleted; the importer also rebuilds a job's declarations on
	// every apply and prunes them when the job is retired.
	JobID uuid.UUID `gorm:"type:uuid;not null;index:idx_dataset_decl_job" json:"job_id"`
	Job   Job       `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	// JobAlias is denormalized so the cross-job lint can resolve producers and
	// build the derivation graph without joining back to jobs.
	JobAlias string `gorm:"type:text;not null;index:idx_dataset_decl_alias" json:"job_alias"`

	// StepName is the producing/consuming step. It is empty for a
	// metadata-level source declaration (direction=source).
	StepName string `gorm:"type:text;not null;default:''" json:"step_name"`

	// Namespace is nullable (reserved for cross-instance datasets, unused in v1).
	// Name is the dataset identity the whole feature keys on.
	Namespace *string `gorm:"type:text;index:idx_dataset_decl_identity,priority:1" json:"namespace,omitempty"`
	Name      string  `gorm:"type:text;not null;index:idx_dataset_decl_identity,priority:2" json:"name"`

	// Direction is one of DatasetDirectionProduces / Consumes / Source.
	Direction string `gorm:"type:text;not null;index:idx_dataset_decl_identity,priority:3" json:"direction"`

	// Freshness / MaxStaleness are the produced dataset's SLO (Go duration
	// strings). ExpectedEvery is the source dataset's cadence expectation. All
	// empty when not applicable to the direction.
	Freshness     string `gorm:"type:text;not null;default:''" json:"freshness,omitempty"`
	MaxStaleness  string `gorm:"type:text;not null;default:''" json:"max_staleness,omitempty"`
	ExpectedEvery string `gorm:"type:text;not null;default:''" json:"expected_every,omitempty"`

	// WatermarkKey is the ##caesium::output key a producing step emits to
	// advance the dataset. Empty in degraded mode (no declared watermark).
	WatermarkKey string `gorm:"type:text;not null;default:''" json:"watermark_key,omitempty"`

	// SchemaJSON is the marshaled inline JSON Schema declared on
	// produces[].schema or consumes[].schema. Empty when no inline schema was
	// declared.
	SchemaJSON string `gorm:"type:text" json:"schema_json,omitempty"`

	// SchemaFrom is the producing step-local schema source (currently "output").
	// Empty for consumed declarations and produced declarations without
	// schemaFrom.
	SchemaFrom string `gorm:"type:text" json:"schema_from,omitempty"`

	// SchemaVersion carries produces[].version for intentional dataset contract
	// breaks. It is zero when unset and unused for consumed/source declarations.
	SchemaVersion int `json:"schema_version,omitempty"`

	// SkipWhenFresh carries metadata.datasets.skipWhenFresh after defaulting.
	// It is evaluated at the cron scheduling seam only and never affects a task's
	// cache identity. Pointer form preserves an explicit false across GORM's
	// default:true create path.
	SkipWhenFresh *bool `gorm:"not null;default:true" json:"skip_when_fresh,omitempty"`

	// External marks a source dataset nobody in Caesium produces.
	External bool `gorm:"not null;default:false" json:"external"`

	// ArrivalBinding is the source dataset's arrival event pattern + watermark
	// JSONPath, stored as JSON. Empty for produced/consumed declarations.
	ArrivalBinding datatypes.JSON `gorm:"type:json" json:"arrival_binding,omitempty"`

	CreatedAt time.Time `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
}

DatasetDeclaration is the persisted *declared* dataset graph — the complement to the *observed* LineageDataset graph (which requires OpenLineage). One row is written per (job, step, dataset, direction) relationship declared in a job's `datasets` surface, rebuilt from the manifest on every apply so a removed declaration is pruned. It stores only scheduling metadata (SLOs, watermark key, arrival binding); it never enters the cache identity and is not a hot per-run table.

Dataset identity is keyed on Name in v1. Namespace is nullable and carried from day one (per the design's Non-goals) so cross-instance namespacing can be added later without a migration rewrite; it is not populated in v1.

type DatasetDerivation

type DatasetDerivation struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`

	// Namespace is nullable (unused in v1); Name is the dataset identity.
	Namespace *string `gorm:"type:text;index:idx_dataset_deriv_identity,priority:1" json:"namespace,omitempty"`
	Name      string  `gorm:"type:text;not null;index:idx_dataset_deriv_identity,priority:2" json:"name"`

	// Decision is one of DatasetDecision* above.
	Decision string `gorm:"type:text;not null" json:"decision"`

	// Reason is a human-readable elaboration of the decision (e.g. "fresh
	// (2h/6h)", "waiting on raw.vendor_x"). Empty when the decision is
	// self-explanatory.
	Reason string `gorm:"type:text;not null;default:''" json:"reason,omitempty"`

	// ConsumedWatermarks snapshots the consumed dataset watermarks the decision
	// evaluated against, as a JSON object keyed by consumed dataset name.
	ConsumedWatermarks datatypes.JSON `gorm:"type:json" json:"consumed_watermarks,omitempty"`

	// RunID is the derived run for a `derived` decision; nil for a skip. A soft
	// reference (no FK) so run pruning never cascades into the audit trail.
	RunID *uuid.UUID `gorm:"type:uuid;index" json:"run_id,omitempty"`

	// CreatedAt is the decision time (append-only; rows are never updated).
	CreatedAt time.Time `gorm:"not null;index:idx_dataset_deriv_created" json:"created_at"`
}

DatasetDerivation is the append-only audit of every evaluator decision for a dataset: whether it derived a run, and if not, why. It is the row behind the "why did/didn't this run" operator surface. Never updated — one row per decision. Not a hot per-run table.

The consumed-watermark snapshot records what the decision saw for the dataset's inputs, so a later reader can reconstruct the derivation without re-deriving state. RunID is the resulting run for a `derived` decision and nil for a skip.

type DatasetState

type DatasetState struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`

	// Namespace is reserved for cross-instance datasets (unused in v1) and Name
	// is the dataset identity the whole feature keys on. Together they are the
	// natural key, enforced by a real UNIQUE index — Namespace is NOT NULL with a
	// ” default (rather than nullable) precisely so the unique index is reliable
	// under SQLite, which treats NULLs as distinct in a UNIQUE index and would
	// otherwise let two rows share one dataset identity. The store maps a nil
	// namespace to ” on every query.
	Namespace string `gorm:"type:text;not null;default:'';uniqueIndex:idx_dataset_state_identity,priority:1" json:"namespace,omitempty"`
	Name      string `gorm:"type:text;not null;uniqueIndex:idx_dataset_state_identity,priority:2" json:"name"`

	// Watermark is the current high-water value emitted by the producing step
	// (or an arrival binding). Empty until the dataset first advances.
	Watermark string `gorm:"type:text;not null;default:''" json:"watermark"`

	// WatermarkRunAt orders the run that set the current Watermark. It gates
	// opaque-string watermarks (git SHAs/UUIDs have no orderable relation): a
	// later-finishing older run must not clobber a newer value, so an opaque
	// write only overwrites when the incoming run is newer than this. Nullable
	// until the first advance.
	WatermarkRunAt *time.Time `json:"watermark_run_at,omitempty"`

	// AdvancedAt is the time the watermark last CHANGED (increased, for
	// orderable values). VerifiedAt is the time a successful run last CONFIRMED
	// the current watermark without changing it. Both nullable until observed.
	AdvancedAt *time.Time `json:"advanced_at,omitempty"`
	VerifiedAt *time.Time `json:"verified_at,omitempty"`

	// Status / Reason are owned by the evaluator (Stream C). The state store
	// leaves them at their defaults.
	Status string `gorm:"type:text;not null;default:'unknown'" json:"status"`
	Reason string `gorm:"type:text;not null;default:''" json:"reason,omitempty"`

	// LastRunID is the run that most recently advanced or verified this dataset.
	// It is a soft reference (no FK constraint) so run pruning never cascades
	// into dataset state.
	LastRunID *uuid.UUID `gorm:"type:uuid;index" json:"last_run_id,omitempty"`

	// ConsumedWatermarks snapshots the watermarks of this dataset's declared
	// inputs as LastRunID STARTED — the view that run actually consumed, not the
	// values current when it finished — so "is my output up to date with my
	// inputs" is a pure row comparison, not a heuristic. JSON object keyed by
	// consumed dataset name. See internal/freshness.Capturer.consumedForRun for
	// the three sources of that start-time view.
	ConsumedWatermarks datatypes.JSON `gorm:"type:json" json:"consumed_watermarks,omitempty"`

	CreatedAt time.Time `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
}

DatasetState is the durable truth every scheduling decision reads: one row per dataset (natural key namespace+name). It distinguishes "a run succeeded" from "the output advanced" — Watermark/AdvancedAt move only on a real watermark change (see internal/freshness.Store.Advance), while VerifiedAt records a successful run that merely confirmed the current value. Freshness is evaluated against max(AdvancedAt, VerifiedAt).

Namespace is nullable and unused in v1 (mirrors DatasetDeclaration); dataset identity keys on Name today. This is NOT a hot per-run table: it is written at run completion and by the evaluator, not on the per-task hot path.

type EventTriggerMatch

type EventTriggerMatch struct {
	ID          uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	EventID     uuid.UUID      `gorm:"type:uuid;index;not null" json:"event_id"`
	Event       IngestedEvent  `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	TriggerID   uuid.UUID      `gorm:"type:uuid;index;not null" json:"trigger_id"`
	MatchedAt   time.Time      `gorm:"not null;index" json:"matched_at"`
	RunsStarted datatypes.JSON `gorm:"type:json" json:"runs_started,omitempty"`
	Skipped     bool           `gorm:"not null;default:false" json:"skipped"`
	SkipReason  string         `gorm:"type:text" json:"skip_reason,omitempty"`
	Error       string         `gorm:"type:text" json:"error,omitempty"`
}

type ExecutionEvent

type ExecutionEvent struct {
	Sequence           uint64     `gorm:"primaryKey;autoIncrement" json:"sequence"`
	Type               string     `gorm:"type:text;index;not null" json:"type"`
	JobID              *uuid.UUID `gorm:"type:uuid;index" json:"job_id,omitempty"`
	RunID              *uuid.UUID `gorm:"type:uuid;index" json:"run_id,omitempty"`
	TaskID             *uuid.UUID `gorm:"type:uuid;index" json:"task_id,omitempty"`
	Payload            []byte     `gorm:"type:json" json:"payload,omitempty"`
	Quarantine         bool       `gorm:"not null;default:false;index" json:"quarantine"`
	BusDispatchPending bool       `gorm:"not null;default:false;index" json:"bus_dispatch_pending"`
	BusDispatchedAt    *time.Time `gorm:"index" json:"bus_dispatched_at,omitempty"`
	CreatedAt          time.Time  `gorm:"not null;index" json:"created_at"`
}

type Incident

type Incident struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
	// Namespace is nullable from day one (design Open Question 4). Empty/NULL
	// means the default namespace; a value scopes the incident to a tenant.
	Namespace *string `gorm:"type:text;index" json:"namespace,omitempty"`

	JobID    uuid.UUID  `gorm:"type:uuid;index;not null" json:"job_id"`
	RunID    *uuid.UUID `gorm:"type:uuid;index" json:"run_id,omitempty"`
	TaskID   *uuid.UUID `gorm:"type:uuid;index" json:"task_id,omitempty"`
	TaskName string     `gorm:"type:text" json:"task_name,omitempty"`

	// Class is the deterministic failure_class the classifier assigned.
	Class string `gorm:"type:text;index;not null" json:"class"`
	// Status is the current position in the incident status machine.
	Status IncidentStatus `gorm:"type:text;index;not null" json:"status"`

	// DedupeKey is the stable correlation key (job_id, task_name, failure_class).
	// It is recorded on every incident (open or closed) for history and querying.
	DedupeKey string `gorm:"type:text;index;not null" json:"dedupe_key"`
	// ActiveDedupeKey enforces "at most one non-terminal incident per dedupe key":
	// it holds DedupeKey while the incident is open and is set NULL on any terminal
	// transition. The unique index only constrains non-NULL rows (dqlite/SQLite
	// semantics), so closed incidents never collide — mirroring the nullable
	// unique-index pattern used by JobRun.ReplayFingerprint. Incident-open is an
	// atomic conditional insert on this column.
	ActiveDedupeKey *string `gorm:"type:text;uniqueIndex:idx_incidents_active_dedupe" json:"-"`

	// OccurrenceCount counts distinct failures folded into this incident (the
	// first open is occurrence 1; an independent same-key failure appends one).
	OccurrenceCount int `gorm:"not null;default:1" json:"occurrence_count"`
	// Attempt counts remediation attempts taken against this incident.
	Attempt int `gorm:"not null;default:0" json:"attempt"`
	// BackfillID storm-controls backfill-originated failures so a single backfill
	// does not open one incident per spawned run.
	BackfillID *uuid.UUID `gorm:"type:uuid;index" json:"backfill_id,omitempty"`

	// RemediationTargetRunID is the run whose success closes the incident as
	// remediated. It advances when a new occurrence folds in.
	RemediationTargetRunID *uuid.UUID `gorm:"type:uuid" json:"remediation_target_run_id,omitempty"`

	// AllowedJobs is the FROZEN job allowlist that scopes the agent's read
	// surface for this incident, computed by the incident manager (an unscoped
	// server principal) from the lineage-impact graph at open time — excluding
	// edges derived from the failing run's own outputs so attacker-crafted
	// ##caesium::output refs cannot widen it. It is a JSON array of job aliases.
	// The agent's scoped token carries a copy; this column is the durable source
	// of truth the session supervisor mints from and the bundle reports.
	AllowedJobs datatypes.JSON `gorm:"type:json" json:"allowed_jobs,omitempty"`

	// LastError is the failing task's error text captured at open, for the feed.
	LastError string `gorm:"type:text" json:"last_error,omitempty"`
	// ResolutionSummary is a short human/agent summary written at close.
	ResolutionSummary string `gorm:"type:text" json:"resolution_summary,omitempty"`
	// Evidence carries classifier evidence (exit code, matched rule) as JSON.
	Evidence datatypes.JSON `gorm:"type:json" json:"evidence,omitempty"`

	OpenedAt  time.Time  `gorm:"not null;index" json:"opened_at"`
	ClosedAt  *time.Time `json:"closed_at,omitempty"`
	CreatedAt time.Time  `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time  `gorm:"not null" json:"updated_at"`
}

Incident records a classified failure that Caesium's incident manager opened from the event bus. Incidents are append-mostly, low-volume catalog rows — NOT a hot per-run table — so they are not listed in hotPathModels().

type IncidentStatus

type IncidentStatus string

IncidentStatus enumerates the states of the incident status machine (design-agent-in-the-loop.md, Phase 0). The lifecycle is:

open → triaging → (awaiting_approval ↔ triaging) → remediated | escalated → closed

with suppressed and abandoned as additional terminal dispositions.

const (
	IncidentStatusOpen             IncidentStatus = "open"
	IncidentStatusTriaging         IncidentStatus = "triaging"
	IncidentStatusAwaitingApproval IncidentStatus = "awaiting_approval"
	IncidentStatusRemediated       IncidentStatus = "remediated"
	IncidentStatusEscalated        IncidentStatus = "escalated"
	IncidentStatusClosed           IncidentStatus = "closed"
	IncidentStatusSuppressed       IncidentStatus = "suppressed"
	IncidentStatusAbandoned        IncidentStatus = "abandoned"
)

func (IncidentStatus) IsTerminal

func (s IncidentStatus) IsTerminal() bool

IsTerminal reports whether the status is a terminal incident disposition.

type IngestedEvent

type IngestedEvent struct {
	ID        uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Type      string         `gorm:"type:text;index;not null" json:"type"`
	Source    string         `gorm:"type:text;index" json:"source,omitempty"`
	Data      datatypes.JSON `gorm:"type:json" json:"data,omitempty"`
	CreatedAt time.Time      `gorm:"not null;index" json:"created_at"`
}

type InternalCAGeneration

type InternalCAGeneration struct {
	Generation    int       `gorm:"primaryKey" json:"generation"`
	CertPEM       string    `gorm:"type:text;not null" json:"cert_pem"`
	KeyCiphertext []byte    `gorm:"type:blob;not null" json:"key_ciphertext"`
	KeyNonce      []byte    `gorm:"type:blob;not null" json:"key_nonce"`
	NotBefore     time.Time `gorm:"not null;index" json:"not_before"`
	NotAfter      time.Time `gorm:"not null;index" json:"not_after"`
	CreatedAt     time.Time `gorm:"not null" json:"created_at"`
}

InternalCAGeneration stores one internal mTLS CA generation. The certificate is public; the private key is AES-GCM sealed by the dispatch/pki package.

type InternalNodeEnrollment

type InternalNodeEnrollment struct {
	ID           string     `gorm:"type:text;primaryKey" json:"id"`
	NodeID       string     `gorm:"type:text;not null;index" json:"node_id"`
	CSRPEM       string     `gorm:"type:text;not null" json:"csr_pem"`
	CSRMac       []byte     `gorm:"type:blob;not null" json:"csr_mac"`
	CAGeneration int        `gorm:"not null;index" json:"ca_generation"`
	CertPEM      *string    `gorm:"type:text" json:"cert_pem,omitempty"`
	Status       string     `gorm:"type:text;not null;index" json:"status"`
	RequestedAt  time.Time  `gorm:"not null;index" json:"requested_at"`
	SignedAt     *time.Time `json:"signed_at,omitempty"`
}

InternalNodeEnrollment is the catalog rendezvous for a node CSR and the leader-signed certificate produced from it.

type Job

type Job struct {
	ID                 uuid.UUID         `gorm:"type:uuid;primaryKey" json:"id"`
	Alias              string            `gorm:"uniqueIndex" json:"alias"`
	TriggerID          uuid.UUID         `gorm:"type:uuid;index;not null" json:"trigger_id"`
	Trigger            Trigger           `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	Labels             datatypes.JSONMap `gorm:"type:json" json:"labels"`
	Annotations        datatypes.JSONMap `gorm:"type:json" json:"annotations"`
	ProvenanceSourceID string            `gorm:"index" json:"provenance_source_id"`
	ProvenanceRepo     string            `json:"provenance_repo"`
	ProvenanceRef      string            `json:"provenance_ref"`
	ProvenanceCommit   string            `json:"provenance_commit"`
	ProvenancePath     string            `json:"provenance_path"`
	MaxParallelTasks   int               `json:"max_parallel_tasks"`
	TaskTimeout        time.Duration     `json:"task_timeout"`
	RunTimeout         time.Duration     `json:"run_timeout"`
	Priority           string            `gorm:"type:text;not null;default:''" json:"priority,omitempty"`
	Concurrency        datatypes.JSON    `gorm:"type:json" json:"concurrency,omitempty"`
	RateLimits         datatypes.JSON    `gorm:"type:json" json:"rate_limits,omitempty"`
	SLA                datatypes.JSON    `gorm:"type:json" json:"sla,omitempty"`
	// SchemaValidation controls runtime output schema validation for this job's tasks.
	// Values: "" (disabled), "warn" (log violations), "fail" (fail task on violation).
	SchemaValidation string         `gorm:"type:text;not null;default:''" json:"schema_validation,omitempty"`
	ReplaySafe       bool           `gorm:"not null;default:false" json:"replay_safe"`
	CacheConfig      datatypes.JSON `gorm:"type:json" json:"cache_config,omitempty"`
	// Remediation persists the job's `metadata.remediation` block verbatim (see
	// pkg/jobdef.MetadataRemediation). It is what makes a job's agent policy
	// ENFORCEABLE rather than merely lintable: the action executor resolves the
	// effective playbook from this column, so a job that narrows what the agent
	// may do autonomously is evaluated under its own policy instead of the
	// deployment-wide default profile. Empty means "the job declared no policy".
	Remediation datatypes.JSON `gorm:"type:json" json:"remediation,omitempty"`
	Paused      bool           `gorm:"not null;default:false" json:"paused"`
	DeletedAt   gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt   time.Time      `gorm:"not null" json:"created_at"`
	UpdatedAt   time.Time      `gorm:"not null" json:"updated_at"`

	LatestRun *JobRun `gorm:"-" json:"latest_run,omitempty"`
}

func (*Job) String

func (j *Job) String() string

type JobRun

type JobRun struct {
	ID           uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	JobID        uuid.UUID      `gorm:"type:uuid;index;not null" json:"job_id"`
	Job          Job            `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	BackfillID   *uuid.UUID     `gorm:"type:uuid;index" json:"backfill_id,omitempty"`
	Backfill     *Backfill      `gorm:"constraint:OnDelete:SET NULL" json:"-"`
	TriggerID    uuid.UUID      `gorm:"type:uuid;index" json:"trigger_id"`
	TriggerType  string         `gorm:"type:text" json:"trigger_type"`
	TriggerAlias string         `gorm:"type:text" json:"trigger_alias"`
	Status       string         `gorm:"type:text;index;not null" json:"status"`
	Priority     int            `gorm:"not null;default:2" json:"priority"`
	Error        string         `json:"error,omitempty"`
	Params       datatypes.JSON `gorm:"type:json" json:"params,omitempty"`
	Quarantine   bool           `gorm:"not null;default:false;index" json:"quarantine"`
	// ReplayFingerprint is the scoped, server-derived idempotency fingerprint
	// for quarantined replay creation. It is nullable so ordinary runs do not
	// participate in the unique index.
	ReplayFingerprint *string        `gorm:"type:text;uniqueIndex:idx_job_runs_replay_fingerprint" json:"replay_fingerprint,omitempty"`
	ReplayOverrides   datatypes.JSON `gorm:"type:json" json:"replay_overrides,omitempty"`
	// SchemaGateOverride records an APPROVED tier-3 `override_schema_gate` action
	// for this ONE run (design-agent-in-the-loop.md action catalog). While set,
	// ValidateTaskOutputSchema / ValidateTaskOutputSchemaInstance skip output
	// schema enforcement for the run's tasks and say so in the log.
	//
	// It lives on the run rather than in Params deliberately: run params feed
	// cache identity (HashInput), so stamping the bypass as a param would re-key
	// the DAG and silently change what the run computes. A column is inert to
	// hashing, which is what "bypass the gate, change nothing else" requires. It
	// is never set by a job definition — only by the approval executor.
	SchemaGateOverride bool       `gorm:"not null;default:false" json:"schema_gate_override,omitempty"`
	StartedAt          time.Time  `gorm:"not null" json:"started_at"`
	CompletedAt        *time.Time `json:"completed_at,omitempty"`
	CreatedAt          time.Time  `gorm:"not null" json:"created_at"`
	UpdatedAt          time.Time  `gorm:"not null" json:"updated_at"`
	Tasks              []*TaskRun `gorm:"foreignKey:JobRunID;constraint:OnDelete:CASCADE" json:"tasks,omitempty"`
	CacheHits          int        `gorm:"-" json:"cache_hits"`
	ExecutedTasks      int        `gorm:"-" json:"executed_tasks"`
	TotalTasks         int        `gorm:"-" json:"total_tasks"`
}

type Jobs

type Jobs []*Job

type KeyScope

type KeyScope struct {
	Jobs  []string    `json:"jobs,omitempty"`
	Agent *AgentClaim `json:"agent,omitempty"`
}

KeyScope represents optional resource scoping for an API key.

A key carries at most one kind of restriction. Jobs restricts a normal principal to a set of job aliases (checked by the deny-by-default route-scope switch). Agent, when present, marks the key as a short-lived agent-session credential bound to exactly one incident's /v1/agent/* tool surface; an agent key is valid for nothing else, regardless of its Jobs field.

type LineageDataset

type LineageDataset struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`

	// TaskRunID is the FK into task_runs.  Records are deleted when the parent
	// task run is deleted.
	TaskRunID uuid.UUID `gorm:"type:uuid;not null;uniqueIndex:idx_lineage_dataset_key,priority:1" json:"task_run_id"`
	TaskRun   TaskRun   `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	// Namespace and Name form the OpenLineage dataset identity.
	Namespace string `gorm:"type:text;not null;uniqueIndex:idx_lineage_dataset_key,priority:2" json:"namespace"`
	Name      string `gorm:"type:text;not null;uniqueIndex:idx_lineage_dataset_key,priority:3" json:"name"`

	// Direction is "input" or "output" from the step's perspective.
	Direction string `gorm:"type:text;not null;uniqueIndex:idx_lineage_dataset_key,priority:4" json:"direction"`

	// FacetSummary is a bounded JSON object holding a digest + small facet
	// summary (step name, output keys, schema keys).  Full facets are emitted
	// via http transport — never stored here.
	FacetSummary datatypes.JSON `gorm:"type:json" json:"facet_summary,omitempty"`

	CreatedAt time.Time `gorm:"not null" json:"created_at"`
}

LineageDataset stores a bounded reference to a dataset observed during a task run — a namespace+name identity plus small facet summaries. Full facets are emitted out-of-process via the existing http transport; dqlite holds only what is needed for impact queries (references + digests).

The natural key is (TaskRunID, Namespace, Name, Direction): a unique index enforces this at the DB level, and callers must upsert (OnConflict DoNothing or DoUpdates) rather than plain-insert to avoid accumulating unbounded rows when a task run emits the same dataset twice. Records are deleted when the parent TaskRun is deleted (constraint:OnDelete:CASCADE).

type NotificationChannel

type NotificationChannel struct {
	ID        uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Name      string         `gorm:"uniqueIndex;not null" json:"name"`
	Type      ChannelType    `gorm:"type:text;not null;index" json:"type"`
	Config    datatypes.JSON `gorm:"type:json;not null" json:"config"`
	Enabled   bool           `gorm:"not null;default:true" json:"enabled"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt time.Time      `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time      `gorm:"not null" json:"updated_at"`
}

NotificationChannel stores a configured notification destination.

type NotificationPolicy

type NotificationPolicy struct {
	ID         uuid.UUID           `gorm:"type:uuid;primaryKey" json:"id"`
	Name       string              `gorm:"uniqueIndex;not null" json:"name"`
	ChannelID  uuid.UUID           `gorm:"type:uuid;index;not null" json:"channel_id"`
	Channel    NotificationChannel `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	EventTypes datatypes.JSON      `gorm:"type:json;not null" json:"event_types"`
	Filters    datatypes.JSON      `gorm:"type:json" json:"filters,omitempty"`
	Enabled    bool                `gorm:"not null;default:true" json:"enabled"`
	DeletedAt  gorm.DeletedAt      `gorm:"index" json:"-"`
	CreatedAt  time.Time           `gorm:"not null" json:"created_at"`
	UpdatedAt  time.Time           `gorm:"not null" json:"updated_at"`
}

NotificationPolicy links event types to channels with optional filters.

type RateLimitToken

type RateLimitToken struct {
	Resource  string    `gorm:"type:text;primaryKey;column:resource" json:"resource"`
	WindowKey string    `gorm:"type:text;primaryKey;column:window_key" json:"window_key"`
	Consumed  int       `gorm:"not null;default:0" json:"consumed"`
	LimitVal  int       `gorm:"column:limit_val;not null" json:"limit_val"`
	ExpiresAt time.Time `gorm:"not null;index" json:"expires_at"`
}

RateLimitToken stores consumed units for one resource/window pair. This is a catalog table: resources are declared on jobs and remain low-cardinality.

func (RateLimitToken) TableName

func (RateLimitToken) TableName() string

type RemediationTimer

type RemediationTimer struct {
	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
	// Namespace is nullable from day one (design Open Question 4).
	Namespace *string `gorm:"type:text;index" json:"namespace,omitempty"`

	IncidentID uuid.UUID `gorm:"type:uuid;index;not null" json:"incident_id"`
	Incident   Incident  `gorm:"constraint:OnDelete:CASCADE" json:"-"`

	// ActionID optionally links the timer to the AgentAction that scheduled it.
	ActionID *uuid.UUID `gorm:"type:uuid;index" json:"action_id,omitempty"`

	// Kind identifies what the sweeper should do when the timer fires
	// (e.g. "snooze_retry").
	Kind string `gorm:"type:text;not null" json:"kind"`
	// Payload carries the fire-time parameters (e.g. target run id) as JSON.
	Payload datatypes.JSON `gorm:"type:json" json:"payload,omitempty"`

	Status RemediationTimerStatus `gorm:"type:text;index;not null;default:'pending'" json:"status"`
	// FireAt is when the timer becomes due. Indexed so the sweeper's due-scan
	// (status = pending AND fire_at <= now) is cheap.
	FireAt  time.Time  `gorm:"not null;index" json:"fire_at"`
	FiredAt *time.Time `json:"fired_at,omitempty"`

	CreatedAt time.Time `gorm:"not null" json:"created_at"`
	UpdatedAt time.Time `gorm:"not null" json:"updated_at"`
}

RemediationTimer is a durable snooze/retry row backing snooze_retry actions. Every existing delay in Caesium is an in-process time.NewTimer lost on restart/failover; this row survives failover so a leader-gated sweeper can fire due timers. Timers are OWNED BY THEIR INCIDENT and cancelled on any terminal transition or human take-over. Low-volume catalog row.

type RemediationTimerStatus

type RemediationTimerStatus string

RemediationTimerStatus enumerates the lifecycle of a durable timer.

const (
	// Pending: not yet due / not yet fired.
	RemediationTimerStatusPending RemediationTimerStatus = "pending"
	// Fired: the sweeper fired the timer's action.
	RemediationTimerStatusFired RemediationTimerStatus = "fired"
	// Cancelled: the owning incident reached a terminal transition or a human
	// took over, so the timer must never fire.
	RemediationTimerStatusCancelled RemediationTimerStatus = "cancelled"
)

type ReprocessPolicy

type ReprocessPolicy string
const (
	ReprocessNone   ReprocessPolicy = "none"
	ReprocessFailed ReprocessPolicy = "failed"
	ReprocessAll    ReprocessPolicy = "all"
)

type Role

type Role string

Role defines the RBAC role hierarchy. admin > operator > runner > viewer

const (
	RoleAdmin    Role = "admin"
	RoleOperator Role = "operator"
	RoleRunner   Role = "runner"
	RoleViewer   Role = "viewer"
)

type RunCheckpoint

type RunCheckpoint struct {
	// RunID identifies the job run.  Stored as text per existing GORM
	// convention for run-owner tables.
	RunID string `gorm:"type:text;primaryKey;index:idx_run_checkpoint_run_seq,priority:1" json:"run_id"`

	// SequenceHigh is the highest terminal_sequence covered by this checkpoint.
	// Recovery applies the checkpoint, then layers task_runs rows with a strictly
	// greater terminal_sequence.  Part of the primary key so each run keeps a
	// history of checkpoints (pruned on archival).
	SequenceHigh int64 `gorm:"primaryKey;autoIncrement:false;index:idx_run_checkpoint_run_seq,priority:2" json:"sequence_high"`

	// OwnerGeneration is the RunLease.Generation of the writing owner — a fence
	// column so a stale owner's checkpoint can be distinguished from the current
	// owner's during a takeover race.
	OwnerGeneration int64 `gorm:"not null" json:"owner_generation"`

	// StateBlob is the serialized RunState snapshot (or delta).  Encoding is an
	// internal detail owned by the checkpoint writer/reader (JSON in v1); the
	// column is opaque bytes.
	StateBlob []byte `gorm:"type:blob;not null" json:"-"`

	// IsIncremental is false for a full snapshot and true for a delta containing
	// only the task states that changed since the prior checkpoint.  Recovery
	// walks back to the most recent full snapshot and applies deltas forward.
	IsIncremental bool `gorm:"not null;default:false" json:"is_incremental"`

	// CreatedAt is the wall-clock write time (diagnostics only; ordering uses
	// SequenceHigh, never timestamps).
	CreatedAt time.Time `gorm:"not null" json:"created_at"`
}

RunCheckpoint persists a point-in-time snapshot of an owner's in-memory DAG state for a run (run-owner mode, CAESIUM_RUN_OWNER_ENABLED=true). Combined with the terminal task_runs rows written after the checkpoint (terminal_sequence > sequence_high), it lets a new owner reconstruct exact run state after the previous owner crashes — recovery bounded by the checkpoint interval.

Like task_runs, a checkpoint is per-run and transactionally local to its run's other rows: it lives in the catalog DB when unsharded, and in the run's hot shard when sharding is enabled (so it appears in both models.All and hotPathModels).

type RunLease

type RunLease struct {
	// RunID identifies the job run. Stored as text per existing GORM convention.
	RunID string `gorm:"type:text;primaryKey" json:"run_id"`

	// OwnerNode is the CAESIUM_NODE_ADDRESS of the owning node.
	OwnerNode string `gorm:"type:text;not null" json:"owner_node"`

	// AcquiredAt is the wall-clock time the lease was written.
	AcquiredAt time.Time `gorm:"not null" json:"acquired_at"`

	// LeaseExpiresAt is when another node may take over via CAS UPDATE.
	LeaseExpiresAt time.Time `gorm:"not null" json:"lease_expires_at"`

	// Generation is incremented on every ownership transfer. All
	// coordination writes include AND owner_generation = <generation> so
	// stale-owner writes are rejected at the DB layer.
	Generation int64 `gorm:"not null" json:"generation"`
}

RunLease records ownership of a job run for the run-owner coordination mode (CAESIUM_RUN_OWNER_ENABLED=true). Only one node owns a run at a time; fencing is enforced via the Generation field and the owner_generation column on task_runs.

This table lives in the catalog DB (cross-run, low-volume) so that any node can answer "who owns run R?" without knowing the run's hot shard.

type RunQueue

type RunQueue struct {
	ID        uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	JobID     uuid.UUID      `gorm:"type:uuid;not null;index:idx_run_queue_job_priority_created,priority:1" json:"job_id"`
	Job       Job            `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	Params    datatypes.JSON `gorm:"type:json" json:"params,omitempty"`
	Priority  int            `gorm:"not null;default:2;index:idx_run_queue_job_priority_created,priority:2,sort:desc" json:"priority"`
	ClaimedBy string         `gorm:"type:text;not null;default:'';index" json:"claimed_by"`
	ClaimedAt *time.Time     `gorm:"index" json:"claimed_at,omitempty"`
	CreatedAt time.Time      `gorm:"not null;index:idx_run_queue_job_priority_created,priority:3,sort:asc" json:"created_at"`
}

func (RunQueue) TableName

func (RunQueue) TableName() string

type SAMLAssertionReplay

type SAMLAssertionReplay struct {
	Issuer      string    `gorm:"type:text;not null;uniqueIndex:idx_saml_assertion_ids_identity" json:"issuer"`
	AssertionID string    `gorm:"type:text;not null;uniqueIndex:idx_saml_assertion_ids_identity" json:"assertion_id"`
	ExpiresAt   time.Time `gorm:"not null;index" json:"expires_at"`
	CreatedAt   time.Time `gorm:"not null" json:"created_at"`
}

SAMLAssertionReplay records accepted SAML assertion IDs so a signed assertion cannot be replayed against another node before it expires.

func (SAMLAssertionReplay) TableName

func (SAMLAssertionReplay) TableName() string

type Session

type Session struct {
	ID                uuid.UUID  `gorm:"type:uuid;primaryKey" json:"id"`
	UserID            uuid.UUID  `gorm:"type:uuid;not null;index" json:"user_id"`
	TokenHash         string     `gorm:"type:text;not null;uniqueIndex" json:"-"`
	CSRFToken         string     `gorm:"type:text;not null" json:"-"`
	AuthMethod        string     `gorm:"type:text" json:"auth_method"`
	CreatedAt         time.Time  `gorm:"not null" json:"created_at"`
	IdleExpiresAt     time.Time  `gorm:"not null" json:"idle_expires_at"`
	AbsoluteExpiresAt time.Time  `gorm:"not null" json:"absolute_expires_at"`
	LastSeenAt        *time.Time `json:"last_seen_at,omitempty"`
	RevokedAt         *time.Time `json:"revoked_at,omitempty"`
	SourceIP          string     `gorm:"type:text" json:"source_ip,omitempty"`
	UserAgent         string     `gorm:"type:text" json:"user_agent,omitempty"`
}

Session is a server-side login session. The opaque token is never stored; only its keyed hash (TokenHash) is persisted.

func (*Session) IsRevoked

func (s *Session) IsRevoked() bool

IsRevoked reports whether the session was explicitly revoked.

type Task

type Task struct {
	// ID, JobID and AtomID (and CreatedAt/UpdatedAt below) carry explicit
	// snake_case json tags so GET /v1/jobs/:id/tasks — which serialises this
	// model directly — matches every other endpoint's casing. Without them Go
	// emitted the Go field names ("ID", "JobID", "AtomID", …), which every
	// consumer had to shim.
	ID           uuid.UUID         `gorm:"type:uuid;primaryKey" json:"id"`
	JobID        uuid.UUID         `gorm:"type:uuid;index;not null" json:"job_id"`
	Job          Job               `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	AtomID       uuid.UUID         `gorm:"type:uuid;index;not null" json:"atom_id"`
	Atom         Atom              `gorm:"constraint:OnDelete:RESTRICT" json:"-"`
	Name         string            `gorm:"type:text;not null;default:''" json:"name"`
	Position     int               `gorm:"not null;default:0" json:"-"`
	Type         string            `gorm:"type:text;not null;default:'task'" json:"type"`
	NodeSelector datatypes.JSONMap `gorm:"type:json" json:"node_selector,omitempty"`
	Retries      int               `gorm:"not null;default:0" json:"retries"`
	RetryDelay   time.Duration     `gorm:"not null;default:0" json:"retry_delay"`
	RetryBackoff bool              `gorm:"not null;default:false" json:"retry_backoff"`
	TriggerRule  string            `gorm:"type:text;not null;default:'all_success'" json:"trigger_rule"`
	ReplaySafe   bool              `gorm:"not null;default:false" json:"replay_safe"`
	// RateLimitResource and RateLimitUnits carry step scheduling metadata from
	// the job definition into the durable task catalog.
	RateLimitResource string `gorm:"type:text;not null;default:''" json:"rate_limit_resource,omitempty"`
	RateLimitUnits    int    `gorm:"not null;default:0" json:"rate_limit_units,omitempty"`
	// FanOutConfig carries step scheduling metadata from the job definition
	// into the durable task catalog. It is JSON of pkg/jobdef.FanOut and is
	// deliberately excluded from the cache identity hash.
	FanOutConfig datatypes.JSON `gorm:"type:json" json:"fan_out_config,omitempty"`
	CacheConfig  datatypes.JSON `gorm:"type:json" json:"cache_config,omitempty"`
	// OutputSchema is a JSON Schema describing this task's expected output keys.
	OutputSchema datatypes.JSON `gorm:"type:json" json:"output_schema,omitempty"`
	// InputSchema maps predecessor task names to JSON Schema fragments describing
	// required keys from each predecessor's output.
	InputSchema datatypes.JSON `gorm:"type:json" json:"input_schema,omitempty"`
	DeletedAt   gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt   time.Time      `gorm:"not null" json:"created_at"`
	UpdatedAt   time.Time      `gorm:"not null" json:"updated_at"`
}

type TaskCache

type TaskCache struct {
	Hash             string         `gorm:"primaryKey;type:text"`
	JobID            uuid.UUID      `gorm:"type:uuid;not null;index:idx_task_cache_job"`
	TaskName         string         `gorm:"type:text;not null"`
	Result           string         `gorm:"type:text;not null"`
	Output           datatypes.JSON `gorm:"type:json"`
	BranchSelections datatypes.JSON `gorm:"type:json"`
	RunID            uuid.UUID      `gorm:"type:uuid;not null"`
	TaskRunID        uuid.UUID      `gorm:"type:uuid;not null"`
	// ResolvedImageDigest records the content digest folded into Hash when the
	// originating task ran with digest pinning on. Nullable: empty when pinning
	// was off. Stored so a cache hit can attest which image content it covers.
	ResolvedImageDigest string `gorm:"type:text"`
	// HashInputBlob is the canonical, secret-redacted decomposition of the
	// HashInput that produced Hash, mirrored from the originating TaskRun so a
	// cache *hit* can also be explained field-by-field. Nullable.
	HashInputBlob datatypes.JSON `gorm:"type:json"`
	// Partitions is the normalized partition list a fan-out PRODUCER emitted,
	// mirrored from its TaskRun so a cache hit on the producer can still expand
	// the downstream group. Without it a warm run replays the producer's result
	// but has nothing to fan out from, and the group collapses to its single
	// template row. Nullable: unset for every non-producer task and for every
	// entry written before this column existed — cache.Entry's entryToModel
	// writes a literal "[]" (not NULL/unset) whenever the ORIGINATING run
	// determined its producer's list, even when that list came out empty
	// (pkg/task/partition.go's partitionAccumulator.finish returns a non-nil
	// []Partition{} for an explicit `##caesium::partitions []`, the documented
	// way to declare zero work). So an unset column distinguishes "no list was
	// ever recorded" from a written "[]" ("recorded, and it was empty") once
	// read back into cache.Entry.Partitions (nil vs a non-nil empty slice,
	// respectively) — the state run.Store.HasFanOutSuccessor's cache-hit gate
	// depends on to tell a legacy entry apart from a legitimately empty one.
	Partitions datatypes.JSON `gorm:"type:json"`
	CreatedAt  time.Time
	ExpiresAt  *time.Time `gorm:"index:idx_task_cache_expires"`
}

TaskCache stores cached task results keyed by identity hash.

type TaskEdge

type TaskEdge struct {
	ID                 uuid.UUID `gorm:"type:uuid;primaryKey"`
	JobID              uuid.UUID `gorm:"type:uuid;index;not null"`
	Job                Job       `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	FromTaskID         uuid.UUID `gorm:"type:uuid;index:idx_task_edge_from_to;not null"`
	FromTask           Task      `gorm:"foreignKey:FromTaskID;constraint:OnDelete:CASCADE" json:"-"`
	ToTaskID           uuid.UUID `gorm:"type:uuid;index:idx_task_edge_from_to;not null"`
	ToTask             Task      `gorm:"foreignKey:ToTaskID;constraint:OnDelete:CASCADE" json:"-"`
	ProvenanceSourceID string    `gorm:"index"`
	ProvenanceRepo     string
	ProvenanceRef      string
	ProvenanceCommit   string
	ProvenancePath     string
	DeletedAt          gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt          time.Time      `gorm:"not null"`
	UpdatedAt          time.Time      `gorm:"not null"`
}

type TaskEdges

type TaskEdges []*TaskEdge

type TaskExecutionBaseline

type TaskExecutionBaseline struct {
	JobID               uuid.UUID `json:"jobId"`
	JobAlias            string    `json:"jobAlias"`
	TaskID              uuid.UUID `json:"taskId"`
	TaskName            string    `json:"taskName"`
	AtomID              uuid.UUID `json:"atomId"`
	BaselineRunID       uuid.UUID `json:"baselineRunId"`
	TriggerID           uuid.UUID `json:"triggerId,omitempty"`
	TriggerType         string    `json:"triggerType,omitempty"`
	TriggerAlias        string    `json:"triggerAlias,omitempty"`
	ReplaySafe          bool      `json:"replaySafe"`
	Quarantine          bool      `json:"quarantine"`
	ComputedHash        string    `json:"computedHash,omitempty"`
	EffectiveHash       string    `json:"effectiveHash,omitempty"`
	HashInputBlobStored bool      `json:"hashInputBlobStored,omitempty"`
}

type TaskExecutionCache

type TaskExecutionCache struct {
	Enabled    bool          `json:"enabled"`
	TTL        time.Duration `json:"ttl"`
	Version    int           `json:"version"`
	PinDigests bool          `json:"pinDigests"`
	DigestTTL  time.Duration `json:"digestTTL"`
	// Chain is the resolved cache.chain mode. Recorded on the descriptor so
	// replay and reproduce rebuild the SAME key: without it a values-mode step
	// replayed from its descriptor would fold predecessor hashes back in and
	// miss on every entry it should have hit. Omitempty keeps descriptors
	// written before this field byte-identical.
	Chain string `json:"chain,omitempty"`
	// TTLNever is the resolved `cache.ttl: never`, carried for the same reason.
	TTLNever            bool   `json:"ttlNever,omitempty"`
	ComputedHash        string `json:"computedHash,omitempty"`
	EffectiveHash       string `json:"effectiveHash,omitempty"`
	HashInputBlobStored bool   `json:"hashInputBlobStored,omitempty"`
}

type TaskExecutionDAG

type TaskExecutionDAG struct {
	Predecessors               []TaskExecutionEdgeRef          `json:"predecessors,omitempty"`
	Successors                 []TaskExecutionEdgeRef          `json:"successors,omitempty"`
	TriggerRule                string                          `json:"triggerRule,omitempty"`
	BranchBehavior             string                          `json:"branchBehavior,omitempty"`
	EdgeMode                   string                          `json:"edgeMode,omitempty"`
	TaskPosition               int                             `json:"taskPosition"`
	OutstandingPredecessors    int                             `json:"outstandingPredecessors"`
	PredecessorOutputs         map[uuid.UUID]map[string]string `json:"predecessorOutputs,omitempty"`
	PredecessorEffectiveHashes map[uuid.UUID]string            `json:"predecessorEffectiveHashes,omitempty"`
}

type TaskExecutionDescriptor

type TaskExecutionDescriptor struct {
	SchemaVersion int       `json:"schemaVersion"`
	CapturedAt    time.Time `json:"capturedAt"`

	Baseline TaskExecutionBaseline `json:"baseline"`
	DAG      TaskExecutionDAG      `json:"dag"`
	Run      TaskExecutionRun      `json:"run"`
	Runtime  TaskExecutionRuntime  `json:"runtime"`
	Timing   TaskExecutionTiming   `json:"timing"`
	Cache    TaskExecutionCache    `json:"cache"`
	Schema   TaskExecutionSchema   `json:"schema"`
	Job      TaskExecutionJob      `json:"job"`

	ContainerSpec  container.Spec            `json:"containerSpec"`
	KubernetesSpec *container.KubernetesSpec `json:"kubernetesSpec,omitempty"`
	SecretRefs     []TaskExecutionSecretRef  `json:"secretRefs,omitempty"`

	// FanOut is present only on a fan-out PRODUCER's descriptor, and only once
	// that producer's execution has determined its partition list. Absent
	// everywhere else, so every descriptor written before this field existed
	// stays byte-identical.
	FanOut *TaskExecutionFanOut `json:"fanOut,omitempty"`
}

TaskExecutionDescriptor is the immutable, per-TaskRun runtime envelope used by quarantined replay. Secret values are never stored; secret refs are recorded with provider identity metadata. Large object/reference capture is out of scope for descriptor schema v1 and must be added explicitly in a later schema version before replay can depend on those refs.

type TaskExecutionEdgeRef

type TaskExecutionEdgeRef struct {
	TaskID   uuid.UUID `json:"taskId"`
	TaskName string    `json:"taskName,omitempty"`
}

type TaskExecutionFanOut

type TaskExecutionFanOut struct {
	// Partitions is the normalized list (key + fingerprint + dependsOn +
	// scalar attributes), in emission order. Encoded with the struct's own JSON
	// tags rather than pkgtask.EncodePartitions, because this field exists to be
	// read back: the canonical wire form flattens attributes to top-level keys,
	// and unmarshalling that back into a Partition silently drops them (the same
	// asymmetry cache.entryToModel documents).
	Partitions []pkgtask.Partition `json:"partitions,omitempty"`
	// PartitionsRecorded distinguishes "this producer ran and determined an
	// EMPTY list" from "no list was ever recorded here" — a descriptor written
	// before this field existed, or a task that is not a producer at all. A nil
	// slice cannot carry that distinction through JSON (omitempty erases the
	// difference between nil and []), and replay must fail closed on the second
	// case while accepting the first, so the discriminator is explicit.
	PartitionsRecorded bool `json:"partitionsRecorded,omitempty"`
	// Groups names the fanned successor steps this producer expanded, by catalog
	// task id. It is what lets replay attribute a group of N instance rows back
	// to the one producer whose list it must re-expand from, without re-deriving
	// fanOut.from against a job definition that may have changed since.
	Groups []TaskExecutionFanOutGroup `json:"groups,omitempty"`
}

TaskExecutionFanOut is the producer-side fan-out record: the normalized partition list one producer emitted, plus the fanned successor steps that list expanded.

It exists so quarantined replay can re-materialize a fanned group WITHOUT re-running the producer. A group's instance set is a runtime property of the producer's output, and replay reconstructs a run from frozen per-TaskRun descriptors — so with nothing recorded there, replay had exactly two options, both wrong (re-expand from a re-executed producer, which reproduces a DIFFERENT run; or resolve one arbitrary sibling), and took the third: refusing fanned baselines outright. This field is the recorded list that refusal was waiting on.

It duplicates TaskRun.Partitions on purpose. That column is live run state, rewritten whenever the producer's row is re-completed; the descriptor is the immutable envelope replay is contractually built from, and is the only one of the two that travels with a descriptor served standalone over /tasks/:task/descriptor.

type TaskExecutionFanOutGroup

type TaskExecutionFanOutGroup struct {
	TaskID   uuid.UUID `json:"taskId"`
	TaskName string    `json:"taskName,omitempty"`
	// Skipped records that the group resolved as skipped instead of expanding,
	// which is what `onEmpty: skip` does for an empty partition list.
	Skipped bool `json:"skipped,omitempty"`
}

TaskExecutionFanOutGroup is one fanned successor step a producer expanded.

type TaskExecutionJob

type TaskExecutionJob struct {
	MaxParallelTasks int               `json:"maxParallelTasks"`
	Labels           map[string]string `json:"labels,omitempty"`
	Annotations      map[string]string `json:"annotations,omitempty"`
	SLA              datatypes.JSON    `json:"sla,omitempty"`
	CacheDefaults    datatypes.JSON    `json:"cacheDefaults,omitempty"`
	TriggerConfig    datatypes.JSONMap `json:"triggerConfig,omitempty"`
}

type TaskExecutionRun

type TaskExecutionRun struct {
	Params map[string]string `json:"params,omitempty"`
}

type TaskExecutionRuntime

type TaskExecutionRuntime struct {
	Engine              AtomEngine `json:"engine"`
	Image               string     `json:"image"`
	ResolvedImageDigest string     `json:"resolvedImageDigest,omitempty"`
	// ParamEnvInterpolation records whether ${CAESIUM_PARAM_*} references in
	// ContainerSpec.Env were expanded for this execution. It is an additive
	// schema-v1 capability bit: descriptors captured before interpolation was
	// introduced omit it and therefore retain their historical literal-env
	// semantics during replay and reproduce.
	ParamEnvInterpolation bool              `json:"paramEnvInterpolation,omitempty"`
	Command               []string          `json:"command,omitempty"`
	CommandRaw            string            `json:"commandRaw,omitempty"`
	WorkDir               string            `json:"workdir,omitempty"`
	TaskType              string            `json:"taskType,omitempty"`
	NodeSelector          map[string]string `json:"nodeSelector,omitempty"`
	RetryCount            int               `json:"retryCount"`
	RetryDelay            time.Duration     `json:"retryDelay"`
	RetryBackoff          bool              `json:"retryBackoff"`
}

type TaskExecutionSchema

type TaskExecutionSchema struct {
	InputSchema  datatypes.JSON `json:"inputSchema,omitempty"`
	OutputSchema datatypes.JSON `json:"outputSchema,omitempty"`
	// ValidationMode fully determines violation behavior in descriptor schema v1.
	ValidationMode string `json:"validationMode,omitempty"`
}

type TaskExecutionSecretRef

type TaskExecutionSecretRef struct {
	Ref                string            `json:"ref"`
	EnvKey             string            `json:"envKey,omitempty"`
	Provider           string            `json:"provider,omitempty"`
	Identity           datatypes.JSONMap `json:"identity,omitempty"`
	Verifiable         bool              `json:"verifiable"`
	UnverifiableReason string            `json:"unverifiableReason,omitempty"`
	IdentityCapturedAt *time.Time        `json:"identityCapturedAt,omitempty"`
}

type TaskExecutionTiming

type TaskExecutionTiming struct {
	TaskTimeout time.Duration `json:"taskTimeout"`
	RunTimeout  time.Duration `json:"runTimeout"`
}

type TaskRun

type TaskRun struct {
	ID             uuid.UUID  `gorm:"type:uuid;primaryKey" json:"id"`
	JobRunID       uuid.UUID  `` /* 127-byte string literal not displayed */
	JobRun         JobRun     `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	TaskID         uuid.UUID  `gorm:"type:uuid;uniqueIndex:idx_taskrun_jobrun_task;index;not null" json:"task_id"`
	Task           Task       `gorm:"constraint:OnDelete:CASCADE" json:"-"`
	AtomID         uuid.UUID  `gorm:"type:uuid;index;not null" json:"atom_id"`
	Engine         AtomEngine `gorm:"type:text;not null" json:"engine"`
	Image          string     `gorm:"not null" json:"image"`
	Command        string     `gorm:"not null" json:"command"`
	Status         string     `gorm:"type:text;index;index:idx_taskrun_claim_priority,priority:1;not null" json:"status"`
	ClaimedBy      string     `gorm:"type:text;index;index:idx_taskrun_claim_priority,priority:5;not null;default:''" json:"claimed_by"`
	ClaimExpiresAt *time.Time `gorm:"index" json:"claim_expires_at,omitempty"`
	ClaimAttempt   int        `gorm:"not null;default:0" json:"claim_attempt"`
	// RateLimitRetryAfter keeps over-limit tasks pending without letting worker
	// claims or owner dispatch pick them back up before the current window rolls.
	RateLimitRetryAfter *time.Time        `gorm:"index" json:"rate_limit_retry_after,omitempty"`
	Attempt             int               `gorm:"not null;default:1" json:"attempt"`
	MaxAttempts         int               `gorm:"not null;default:1" json:"max_attempts"`
	Priority            int               `gorm:"not null;default:2;index:idx_taskrun_claim_priority,priority:3,sort:desc" json:"priority"`
	NodeSelector        datatypes.JSONMap `gorm:"type:json" json:"node_selector,omitempty"`
	Hash                string            `gorm:"type:text;index" json:"-"`
	// EffectiveHash is the identity this task presents to its DOWNSTREAM
	// consumers when a value-verified short-circuit was proven (design Component
	// 5 / D2). Nullable: empty means "use Hash" — the common case. When this
	// task re-executed because its OWN identity changed (Hash != a prior run's)
	// but it produced byte-identical output to a prior successful run, this is
	// set to that prior run's identity hash. Downstream PredecessorHashes reads
	// COALESCE(effective_hash, hash), so a downstream task whose only changed
	// input was this step sees an UNCHANGED predecessor and cache-hits — proven,
	// not heuristic. Hash itself is left untouched so this task's own receipt /
	// `caesium why` still reflect its true identity. See
	// cache.EquivalentPriorHash for the proof and its default-to-rerun guards.
	EffectiveHash    string         `gorm:"type:text" json:"-"`
	Result           string         `json:"result,omitempty"`
	Output           datatypes.JSON `gorm:"type:json" json:"output,omitempty"`
	BranchSelections datatypes.JSON `gorm:"type:json" json:"branch_selections,omitempty"`
	Quarantine       bool           `gorm:"not null;default:false;index" json:"quarantine"`
	CacheHit         bool           `gorm:"not null;default:false" json:"cache_hit"`
	CacheEnabled     bool           `gorm:"not null;default:false" json:"-"`
	CacheTTL         time.Duration  `gorm:"not null;default:0" json:"-"`
	CacheVersion     int            `gorm:"not null;default:0" json:"-"`
	// ReplaySafe snapshots the effective job/step replaySafe mark when this
	// task run is materialized. Replay authorization reads this baseline value,
	// not the mutable live job definition.
	ReplaySafe bool `gorm:"not null;default:false" json:"replay_safe"`
	// CachePinDigests snapshots whether image-digest pinning is in effect for
	// this task. Like CacheEnabled/CacheTTL/CacheVersion it is scheduler-set on
	// the row so distributed workers behave identically to local execution
	// without reloading the job definition.
	CachePinDigests bool `gorm:"not null;default:false" json:"-"`
	// CacheDigestTTL snapshots how long a resolved tag->digest mapping may be
	// reused before re-resolution (0 = re-resolve every check). Scheduler-set so
	// distributed workers apply the same freshness window as local execution.
	CacheDigestTTL time.Duration `gorm:"not null;default:0" json:"-"`
	// CacheChain snapshots the resolved cache.chain mode ("transitive" default,
	// or "values"). Scheduler-set beside CachePinDigests so a distributed worker
	// builds the same identity key as local execution without reloading the job
	// definition. Empty means transitive — that is what every row written before
	// this column existed carries, and it is the mode whose hash is unchanged.
	CacheChain string `gorm:"type:text" json:"-"`
	// CacheTTLNever snapshots the literal `cache.ttl: never`, which suppresses
	// the cache entry's expiry entirely (nil ExpiresAt) regardless of any
	// inherited TTL default. It is distinct from CacheTTL == 0, which means "no
	// explicit TTL" and still inherits CAESIUM_CACHE_TTL.
	CacheTTLNever bool `gorm:"not null;default:false" json:"-"`
	// ResolvedImageDigest records the content digest (sha256:...) the image tag
	// resolved to when pinning is on. Nullable: empty/unset when pinning is off
	// or the digest could not be resolved (in which case the cache key falls
	// back to the literal tag).
	ResolvedImageDigest string `gorm:"type:text" json:"resolved_image_digest,omitempty"`
	// HashInputBlob is the canonical, secret-redacted, field-by-field JSON
	// decomposition of the HashInput that produced Hash. Nullable: written only
	// when caching is enabled and the hash was computed, left null otherwise.
	// It lets `caesium why` report *which* input changed between two runs
	// instead of only "the hashes differ". Env values are redacted in the blob;
	// see cache.HashInput.CanonicalJSON.
	HashInputBlob    datatypes.JSON `gorm:"type:json" json:"-"`
	CacheOriginRunID *uuid.UUID     `gorm:"type:uuid;index" json:"cache_origin_run_id,omitempty"`
	CacheCreatedAt   *time.Time     `json:"cache_created_at,omitempty"`
	CacheExpiresAt   *time.Time     `gorm:"index" json:"cache_expires_at,omitempty"`
	// OutputSchema snapshots the task's declared runtime output schema onto the task run.
	OutputSchema datatypes.JSON `gorm:"type:json" json:"-"`
	// SchemaValidation snapshots the job's schema validation mode onto the task run.
	SchemaValidation string `gorm:"type:text;not null;default:''" json:"-"`
	// SchemaViolations stores any output schema violations detected at runtime.
	SchemaViolations datatypes.JSON `gorm:"type:json" json:"schema_violations,omitempty"`
	// ExitCode is the raw process exit code the container/pod reported at task
	// completion. Every engine folds this code into an atom.Result and discards
	// it today; this column preserves it so the incident classifier can map
	// exit-code + log-tail patterns to a failure_class (design Phase 0). Nullable:
	// unset (NULL) when the task never produced an exit code (engine wait error,
	// startup failure before a code was assigned). A value of 0 is a real,
	// captured success code — distinct from NULL "never captured".
	ExitCode                *int           `gorm:"type:integer" json:"exit_code,omitempty"`
	ExecutionDescriptor     datatypes.JSON `gorm:"type:json" json:"-"`
	LogText                 string         `gorm:"type:text" json:"-"`
	LogTruncated            bool           `gorm:"not null;default:false" json:"-"`
	Error                   string         `json:"error,omitempty"`
	RuntimeID               string         `json:"runtime_id,omitempty"`
	OutstandingPredecessors int            `gorm:"not null;index:idx_taskrun_claim_priority,priority:2" json:"outstanding_predecessors"`
	// OwnerGeneration is set to the RunLease.Generation of the owning node when
	// run-owner mode is active.  Every coordination write by the owner
	// includes AND (owner_generation = ? OR owner_generation = 0) in its WHERE
	// clause — the OR = 0 keeps legacy rows (and flag-off rows) mutable by any
	// node so the migration path stays gradual.  Defaults to 0.
	OwnerGeneration int64 `gorm:"not null;default:0" json:"owner_generation,omitempty"`
	// TerminalSequence is the per-run monotonic, dense sequence number stamped on
	// a task_runs row when it reaches a terminal status under run-owner mode.  It
	// shares a number space with run_checkpoints.sequence_high so failure
	// recovery can replay "terminal rows since the last checkpoint" in a
	// deterministic order (NOT wall-clock, which is skew-prone).  0 means
	// "never stamped" (non-owner mode, or not yet terminal).  The composite index
	// (job_run_id, terminal_sequence) makes the post-checkpoint tail scan cheap.
	TerminalSequence int64      `gorm:"not null;default:0;index:idx_taskrun_terminal_seq,priority:2" json:"terminal_sequence,omitempty"`
	StartedAt        *time.Time `json:"started_at,omitempty"`
	CompletedAt      *time.Time `json:"completed_at,omitempty"`
	CreatedAt        time.Time  `gorm:"not null;index:idx_taskrun_claim_priority,priority:4,sort:asc" json:"created_at"`
	UpdatedAt        time.Time  `gorm:"not null" json:"updated_at"`

	// PartitionValue is empty for an unfanned task. For a fanned instance it is
	// the partition key (the value injected as CAESIUM_PARTITION).
	PartitionValue string `gorm:"type:text;not null;default:''" json:"partition_value,omitempty"`
	// PartitionRetryPending marks an operator-requested per-partition retry that
	// has not reached a terminal outcome yet. Store.Complete uses this durable
	// provenance marker to distinguish a retry that landed in the local
	// engine's shutdown window from an ordinary never-dispatched fan-out row.
	// It is set only by RetryPartition and cleared by every terminal transition.
	PartitionRetryPending bool `gorm:"not null;default:false" json:"-"`
	// PartitionIndex is emission order (never topological order). Unfanned and
	// the rewritten template row are 0. Unique with (job_run_id, task_id).
	//
	// The composite index kept its pre-fan-out NAME (idx_taskrun_jobrun_task)
	// while changing shape from a non-unique two-column index to a UNIQUE
	// three-column one. GORM's AutoMigrate matches indexes by name only and
	// leaves an existing one untouched, so these tags alone would give a fresh
	// database the correct index and every existing deployment the old one, with
	// the uniqueness invariant silently unenforced. The explicit migration in
	// pkg/db/migrations.go (MigrateTaskRunUniquePartitionIndex) drops the stale
	// index before AutoMigrate runs. Do not rename or re-shape this index without
	// updating that migration.
	PartitionIndex int `gorm:"not null;default:0;uniqueIndex:idx_taskrun_jobrun_task" json:"partition_index"`
	// PartitionCount is 0 for unfanned tasks and N for every instance of a
	// fanned group.
	PartitionCount int `gorm:"not null;default:0" json:"partition_count"`
	// PartitionFingerprint is the optional per-unit content address
	// (sha256:<64 hex>). Empty when the producer emitted a string-form partition.
	PartitionFingerprint string `gorm:"type:text;not null;default:''" json:"partition_fingerprint,omitempty"`
	// PartitionAttributes is the JSON object of scalar attributes from a
	// structured partition (omit-when-empty).
	PartitionAttributes datatypes.JSON `gorm:"type:json" json:"partition_attributes,omitempty"`
	// PartitionDependsOn is the JSON array of sibling keys this instance waits
	// on. Empty for string-form partitions and for instances with no in-group
	// edges.
	PartitionDependsOn datatypes.JSON `gorm:"type:json" json:"partition_depends_on,omitempty"`
	// Partitions is the normalized emitted list, persisted on the *producer's*
	// row for observability/why/replay. Empty on consumer instances.
	Partitions datatypes.JSON `gorm:"type:json" json:"partitions,omitempty"`
}

type Tasks

type Tasks []*Task

type Trigger

type Trigger struct {
	ID                 uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Alias              string         `gorm:"index" json:"alias"`
	Type               TriggerType    `gorm:"index;not null" json:"type"`
	NormalizedPath     string         `gorm:"index" json:"-"`
	Configuration      string         `json:"configuration"`
	ProvenanceSourceID string         `gorm:"index" json:"provenance_source_id"`
	ProvenanceRepo     string         `json:"provenance_repo"`
	ProvenanceRef      string         `json:"provenance_ref"`
	ProvenanceCommit   string         `json:"provenance_commit"`
	ProvenancePath     string         `json:"provenance_path"`
	DeletedAt          gorm.DeletedAt `gorm:"index" json:"-"`
	CreatedAt          time.Time      `gorm:"not null" json:"created_at"`
	UpdatedAt          time.Time      `gorm:"not null" json:"updated_at"`
}

func (*Trigger) ApplyDerivedFields

func (t *Trigger) ApplyDerivedFields() error

func (*Trigger) BeforeSave

func (t *Trigger) BeforeSave(*gorm.DB) error

type TriggerType

type TriggerType string
const (
	TriggerTypeCron      TriggerType = "cron"
	TriggerTypeHTTP      TriggerType = "http"
	TriggerTypeEvent     TriggerType = "event"
	TriggerTypeFreshness TriggerType = "freshness"
)

type Triggers

type Triggers []*Trigger

type User

type User struct {
	ID          uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Issuer      string         `gorm:"type:text;not null;uniqueIndex:idx_users_identity" json:"issuer"`
	Subject     string         `gorm:"type:text;not null;uniqueIndex:idx_users_identity" json:"subject"`
	Email       string         `gorm:"type:text;index" json:"email"`
	DisplayName string         `gorm:"type:text" json:"display_name,omitempty"`
	Groups      datatypes.JSON `gorm:"type:json" json:"groups,omitempty"`
	Role        Role           `gorm:"type:text;not null" json:"role"`
	CreatedAt   time.Time      `gorm:"not null" json:"created_at"`
	LastLoginAt *time.Time     `json:"last_login_at,omitempty"`
	DisabledAt  *time.Time     `json:"disabled_at,omitempty"`
}

User is a human identity provisioned just-in-time from an external IdP.

func (*User) IsDisabled

func (u *User) IsDisabled() bool

IsDisabled reports whether the user account has been disabled.

type WebhookEvent

type WebhookEvent struct {
	ID                   uuid.UUID      `gorm:"type:uuid;primaryKey" json:"id"`
	Path                 string         `gorm:"type:text;index;not null" json:"path"`
	Source               string         `gorm:"type:text;index" json:"source,omitempty"`
	ReceivedAt           time.Time      `gorm:"not null;index" json:"received_at"`
	Status               string         `gorm:"type:text;index;not null" json:"status"`
	EventID              uuid.UUID      `gorm:"type:uuid;index" json:"event_id,omitempty"`
	EventMatchedTriggers int            `gorm:"not null;default:0" json:"event_matched_triggers"`
	EventRunsStarted     int            `gorm:"not null;default:0" json:"event_runs_started"`
	HTTPTriggersAccepted int            `gorm:"not null;default:0" json:"http_triggers_accepted"`
	HTTPRunsStarted      int            `gorm:"not null;default:0" json:"http_runs_started"`
	HTTPTriggerIDs       datatypes.JSON `gorm:"type:json" json:"http_trigger_ids,omitempty"`
	HTTPJobIDs           datatypes.JSON `gorm:"type:json" json:"http_job_ids,omitempty"`
	AuthFailures         datatypes.JSON `gorm:"type:json" json:"auth_failures,omitempty"`
	Error                string         `gorm:"type:text" json:"error,omitempty"`
}

Jump to

Keyboard shortcuts

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