Athena

Athena Contracts

The canonical contract model for Athena client identity, capabilities, connection, routing, and backend dispatch.

Athena is strongest when the top level owns the truth.

That means Athena, not PostgreSQL, Scylla, Supabase, or S3, defines:

  • what a client is
  • what operations a client is allowed to perform
  • how a request is resolved
  • what response and error envelopes look like
  • what observability metadata is emitted

This page documents the contract model that keeps Athena in charge even when multiple backends sit underneath it.

Use this page as the architecture contract source of truth when introducing new backends, refactoring route handlers, or deciding whether a feature belongs to Athena core or to a backend-specific driver.

Mental model

The important boundary is simple: Athena decides identity, policy, dispatch, and envelope shape. Drivers only implement backend work beneath that decision.

Contract stack

Athena should be read as a stack of contracts, from most authoritative to least:

  1. Client identity contract: what an Athena client is.
  2. Lifecycle contract: whether that client is active, frozen, or inactive.
  3. Capability contract: what that client is allowed to do.
  4. Connection contract: what engine-specific connection data exists.
  5. Resolver contract: how Athena turns a client name into a runtime backend.
  6. Dispatch contract: how routes call the resolved backend.
  7. Driver contract: what a backend driver must implement.
  8. Backend extension contracts: what remains intentionally engine-specific.

1. Client identity contract

An Athena client is a logical backend binding, not a Postgres connection string with optional metadata.

Canonical shape:

pub struct AthenaClientDefinition {
    pub client_name: String,
    pub engine: AthenaEngine,
    pub lifecycle: AthenaClientLifecycle,
    pub capabilities: AthenaCapabilities,
    pub connection: AthenaConnection,
    pub metadata: serde_json::Value,
}

Rules:

  • client_name is the stable Athena-facing identifier used by X-Athena-Client.
  • engine is explicit and never inferred from unrelated fields when a first-class engine tag exists.
  • metadata is supplementary. It may enrich a client definition, but it must not be the only place where Athena learns the client's core identity.
  • Route handlers should consume AthenaClientDefinition, not raw catalog rows.

2. Lifecycle contract

Lifecycle is Athena-owned state, not backend-owned health.

Suggested shape:

pub enum AthenaClientLifecycle {
    Active,
    Frozen,
    Inactive,
}

Semantics:

  • Active: Athena may resolve and dispatch requests.
  • Frozen: Athena knows the client but intentionally blocks execution.
  • Inactive: Athena keeps the definition but does not treat it as runnable.

Important distinction:

  • Lifecycle is a policy decision.
  • Runtime connectivity is an operational fact.

A client can be Active but currently unavailable because its backend cannot be reached. Athena should keep those ideas separate.

3. Capability contract

Capabilities are the most important contract after identity because they keep Athena honest about what “compatible” means.

Suggested shape:

pub struct AthenaCapabilities {
    pub gateway_query: bool,
    pub raw_sql: bool,
    pub raw_cql: bool,
    pub schema_read: bool,
    pub migrations_read: bool,
    pub provisioning: bool,
    pub deferred_query: bool,
    pub cdc: bool,
    pub object_read: bool,
    pub object_write: bool,
}

Rules:

  • Routes check capabilities before touching backend-specific code.
  • Unsupported operations fail as unsupported Athena capabilities, not as accidental backend errors.
  • New engines become safe to add because Athena can say “this client exists, but it does not support this route family.”

4. Connection contract

Connection data must be a tagged union, not a Postgres-first row with sidecar metadata for everything else.

Suggested shape:

pub enum AthenaConnection {
    Postgres(PostgresConnectionInfo),
    Scylla(ScyllaConnectionInfo),
    S3(S3ConnectionInfo),
}

Rules:

  • Athena chooses the connection variant based on the client definition.
  • Route handlers never pattern-match on ad hoc metadata blobs.
  • Connection structs are backend-specific, but the enum is Athena-owned.

5. Resolver contract

Athena needs two resolution stages:

  1. Resolve the logical client definition.
  2. Resolve the runtime backend handle.

Suggested shape:

pub enum AthenaResolvedBackend {
    Postgres(PostgresBackendHandle),
    Scylla(ScyllaBackendHandle),
    S3(S3BackendHandle),
}

pub trait AthenaBackendResolver {
    async fn resolve_client(
        &self,
        state: &AppState,
        client_name: &str,
    ) -> Result<AthenaClientDefinition, AthenaResolveError>;

    async fn resolve_backend(
        &self,
        state: &AppState,
        client: &AthenaClientDefinition,
    ) -> Result<AthenaResolvedBackend, AthenaResolveError>;
}

Rules:

  • X-Athena-Client resolves to a client definition first, never directly to a PgPool.
  • Runtime registries are implementation details of backend resolution.
  • Missing clients, frozen clients, and unreachable backends should produce different Athena errors.

6. Dispatch contract

Every route family should follow the same top-level flow:

auth -> resolve client -> require capability -> resolve backend -> execute -> normalize response

That means route handlers should depend on Athena contracts like:

  • AthenaClientDefinition
  • capability checks
  • AthenaResolvedBackend
  • shared response and error builders

They should not depend directly on:

  • PgPool
  • ClientConnectionTarget
  • ScyllaConnectionInfo
  • backend-specific catalog parsing

7. Driver contract

Drivers are Athena’s backend adapters. They implement execution and backend-specific metadata access, but they do not define Athena identity.

Suggested execution-facing traits:

#[async_trait]
pub trait AthenaQueryBackend {
    async fn execute_raw_query(
        &self,
        request: AthenaRawQueryRequest,
    ) -> Result<AthenaQueryResult, AthenaBackendError>;
}

#[async_trait]
pub trait AthenaSchemaBackend {
    async fn list_tables(&self) -> Result<Vec<AthenaTableInfo>, AthenaBackendError>;
}

#[async_trait]
pub trait AthenaProvisioningBackend {
    async fn provision(
        &self,
        request: AthenaProvisionRequest,
    ) -> Result<AthenaProvisionResult, AthenaBackendError>;
}

Rules:

  • Drivers implement Athena contracts, not the other way around.
  • A backend only implements the traits it truly supports.
  • Athena route handlers remain stable even when driver implementations change.

8. Backend extension contracts

Not every feature should be universal. Athena should explicitly model backend-specific surfaces.

BackendAthena-owned contractBackend-owned extension
PostgreSQLclient identity, capabilities, dispatch, error shapepool lifecycle, SQL execution, information_schema, provisioning
Scyllaclient identity, capabilities, dispatch, error shapeCQL execution, keyspace/session behavior, cluster node topology
S3client identity, capabilities, dispatch, error shapebucket/object semantics, signed URL generation, storage metadata

Rule:

  • Athena owns the stable platform surface.
  • Backend extensions are allowed only below that surface.

Route family contracts

Each route family should advertise the capability it requires and whether it is intended to be engine-neutral or engine-specific.

Route familyRequired capabilityIntended scope
/gateway/querygateway_queryAthena-level query execution contract
/query/sql and /gateway/sqlraw_sql or raw_cql depending on request languageEngine-aware raw query contract
/query/countquery capability plus count supportAthena-level, but only where the engine can support it honestly
/schema/*schema_readBackend-specific introspection behind an Athena contract
/schema/migrationsmigrations_readUsually Postgres/Supabase-specific
/management/* provisioningprovisioningExplicitly capability-gated, not universal by default
/storage/*object_read / object_writeStorage-family contract
/pipelinespipeline execution plus source/sink capability checksAthena orchestration contract

Current drift to remove

Athena’s current implementation still contains several Postgres-shaped assumptions that this contract model is meant to remove.

Catalog drift

  • Postgres connection fields are first-class in catalog storage.
  • Non-Postgres backends are still partially inferred from metadata.

Desired end state:

  • engine is explicit
  • connection is typed
  • metadata is supplementary only

Runtime drift

  • some resolution paths still ask for a Postgres pool first
  • some route helpers still talk in terms of “Postgres client” rather than “Athena client”

Desired end state:

  • route helpers resolve Athena clients first
  • backend handles are resolved afterward

Capability drift

  • some routes are implicitly Postgres-only without saying so
  • some backend differences appear as implementation quirks rather than explicit feature flags

Desired end state:

  • unsupported behavior is reported through Athena capability checks

Current route status

This is the practical contract state Athena should communicate today while the dominance refactor is still underway.

ConcernCurrent practical state
Client identitystill partially Postgres-shaped in catalog and runtime helpers
Raw Scylla executionavailable for the Scylla path, but not yet a fully equal first-class platform contract
Deferred /gateway/querynot yet universal across backends
Schema introspectionstill effectively Postgres/Supabase oriented
Provisioning and managementstill heavily Postgres-oriented
Storage operationsseparate storage-family contract, not part of the SQL/CQL contract

Response and error contract

Even when execution diverges by backend, Athena should preserve a stable outer contract:

  • consistent auth failure envelope
  • consistent not-found / frozen / inactive distinctions
  • stable request correlation and trace metadata
  • stable metrics and operation logs
  • backend name recorded as metadata, not leaked as the sole contract shape

Rule:

  • Athena normalizes the caller-facing envelope.
  • Drivers contribute detail, but do not own the public response contract.

Observability contract

Every routed operation should emit Athena-level telemetry:

  • request id
  • logical client name
  • resolved backend engine
  • route family
  • operation outcome
  • latency and availability signals

Backend-specific diagnostics may be attached, but the top-level telemetry dimensions must remain Athena-native.

SDK contract

The SDKs should mirror Athena’s contract hierarchy:

  • client selects an Athena logical client
  • Athena resolves the engine internally
  • SDK APIs expose capability-aware operations
  • engine-specific escape hatches are explicit, not accidental

Rule:

  • the SDK should not force callers to think in backend-native routing terms unless they intentionally opt into a backend-specific escape hatch

Anti-contracts

These are the invariants Athena should reject:

  • “an Athena client is a pg_uri
  • “route handlers may resolve directly to PgPool
  • “metadata is where backend identity lives forever”
  • “backend-specific implementation failures are the same thing as unsupported Athena features”
  • “compatibility means pretending every backend supports the same semantics”
  1. Introduce Athena-owned client, connection, lifecycle, and capability types.
  2. Add a catalog adapter that can produce those types from current storage.
  3. Add a resolver that returns AthenaResolvedBackend.
  4. Move query and gateway route families onto that resolver.
  5. Convert schema, provisioning, storage, and pipeline families into explicit capability-checked contracts.
  6. Replace the remaining Postgres-shaped catalog assumptions with engine-neutral storage.