Skip to main content

Core Invariants & Business Rules

These are the platform's guarantees: the invariants the core enforces (or, where noted, the contract it asks plugins to honour). They're consolidated here as a reference; the reasoning behind each lives in the relevant conceptual article.

Boundary

  • The core never reads from or writes to plugin-owned tables. It has no knowledge of their shape.
  • Plugin tables may reference core tables (workspace, workflow_execution) via foreign keys; core tables never reference plugin tables.
  • Domain-specific business rules live in the plugin, never in the core.
  • By contract, plugins mutate core tables only through core services, with a single startup exception (seeding their entity and workspace_status rows). This is a discipline the contract asks for, not a mechanism the core enforces — a plugin runs with database access, so honouring it is the plugin developer's responsibility.

Workspaces & status

  • Core workspaces are never deleted. There is no is_deleted / is_archived on the core workspace table; deletion and archival are plugin concerns on the join table. This preserves execution history and financial data by design.
  • Workspace status is scoped to an entity type (workspace_status.entity_id), unique per (entity_id, slug). Two plugins may reuse the same slug.
  • A workflow may launch only from a workspace in one of its eligible statuses, and on success transitions the workspace to its single resulting status. The backend owns this transition — it never relies on UI assumptions — and validates that a workflow's eligible/resulting statuses share the workflow's entity type.

Configuration & cost

  • prompt.active_prompt_version_id must reference a version belonging to the same prompt.
  • Configuration validity is derived from upstream enablement, not stored; the disable cascade propagates from any disabled dependency to the workflows above it.
  • Cost is core-owned. Workflows report consumption only; the core computes cost_usd at ingestion using current registry pricing. Each log row carries its own cost_usd; cumulative cost is derived at query time (no running-total column).
  • Financial reporting always derives from workflow_execution_log; plugin-level deletion or archival never affects it.

Execution & snapshots

  • A workflow_execution stores four immutable snapshots (workflow_config, service_config, system, workspace), all JSONB NOT NULL; the webhook payload is assembled from them (there is no separate context-fetch endpoint).
  • The execution always references the original workspace it launched against, even when a workflow creates a new one.
  • A dispatch failure marks the execution failed_permanent; a result-handler throw rolls back and marks failed_permanent. Workflow-reported, reconciler, and operator terminations mark failed_transient. Only failed_transient is retryable, and retry replays the original snapshots exactly.
  • Truthfulness Invariant: the platform never marks an execution terminal while the engine may still be running. The reconciler never marks completed — completion requires the /complete result payload.
  • Threshold enforcement is >= (reaching a limit exactly is a breach); a value of 0 means unlimited.

Auth

  • Human and machine auth are separate concerns: user_jwt_secret for operators, workflow_jwt_secret for API Keys, and the two must never be identical (enforced at startup).
  • Both token classes revoke by jti denylist, not raw-token storage. API Keys expire in 30 days; the full key is shown only once and never stored.

Plugin contract

  • Every plugin provides an entity row, one or more workspace statuses, an entity-object table, a {entity_slug}_workspace join table (with is_deleted/is_archived), a manifest, and migrations — and supplies four extension points (resultHandler, workspaceSnapshotProvider, dashboardStatsProvider, workspaceDisplayResolver).
  • The core validates plugin structure at startup; a plugin that fails validation is skipped, and the platform starts without it.