Docs menu

Concepts

The few ideas Tidewater is built on: workspaces, pipelines, runs, assets, expectations, lineage and alerts, and how they fit together.

Last updated

Tidewater has a small number of ideas. Once you know them, the rest of the product is predictable.

Workspaces

A workspace holds everything: pipelines, assets, owners, alert rules and API tokens. Most companies use one workspace per environment, for example production and staging. Workspaces never share data, and each one is stored in one region.

Pipelines

A pipeline is one scheduled job or stream that produces data. An Airflow DAG, a dbt job, a Spark application and a Kafka consumer group are each one pipeline. A pipeline has a name, a source system, an owner, and the assets it writes.

Pipelines are what you count and pay for. A pipeline that is paused does not count.

Runs

A run is one execution of a pipeline. It has a status (started, succeeded or failed), a start time, an end time and optionally the number of rows written. Runs come from integrations or from the API.

A run is identified by a run_key that you choose. Reporting the same key again updates the run, which is why retries are safe.

Assets

An asset is something that holds data and that people depend on: a table, a model, a topic or a dashboard. Assets are connected by lineage, and they are what alerts talk about. When you say “the orders table is late”, analytics.orders is the asset.

Expectations

An expectation is a statement of what normal looks like for a pipeline or an asset. Tidewater supports four kinds.

KindWhat it checksExample
FreshnessThe newest data is recent enoughCurrent by 06:00 on weekdays
VolumeThe number of rows is in rangeAt least 900,000 rows a day
SchemaColumns have not changed unexpectedlyNo dropped or retyped columns
Custom SQLA query you write returns what you expectNo orders with a negative total

Fixed and learned thresholds

You can state an expectation yourself, or let Tidewater learn it. A learned threshold is built from at least 14 days of history. Tidewater models the normal range for each day of the week and flags values outside it. Learned thresholds suit volume and run duration. Freshness works best with a deadline written by a person, because a deadline is a promise, not a pattern.

Lineage

Lineage is the graph of which assets feed which. Tidewater builds it by reading SQL from your warehouse query logs and your transformation tool, so it works without changes to your code. Edges are recorded at the table level and, on Business and Enterprise plans, at the column level.

Lineage is what turns an alert into a decision. When the orders table is late, the lineage tells you that three models and two dashboards depend on it, and who owns each.

Alerts

An alert opens when an expectation is not met and closes when it is. An alert has a state:

  1. Open. The problem is current and nobody has said they are looking at it.
  2. Acknowledged. A person has seen it. Reminders stop, but the alert stays open.
  3. Resolved. The data has recovered. Tidewater closes the alert and records how long it lasted.

An alert carries its impact: the list of assets that depend on the affected one. Alert rules decide who receives it, using the owner of the asset, an urgency, and optional quiet hours.

Owners and groups

An owner is a team or a person. Owners come from your dbt metadata, orchestrator tags or settings in Tidewater. A group is a named set of pipelines that share an owner, an expectation and an alert rule, for example “finance close”.

Webhooks

Tidewater can send an event to your own HTTPS endpoint when an alert opens, is acknowledged or resolves. Each request is signed, so you can check that it came from Tidewater. The signature is an HMAC of the raw request body with your webhook secret, sent in the Tidewater-Signature header.

Python

import hashlib
import hmac

def is_valid(secret: bytes, body: bytes, signature: str) -> bool:
expected = hmac.new(secret, body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)

TypeScript

import { createHmac, timingSafeEqual } from 'node:crypto';

export function isValid(secret: string, body: string, signature: string): boolean {
const expected = createHmac('sha256', secret).update(body).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}

curl

# Compute the expected signature of a saved request body.
openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" body.json

How it fits together

Your orchestrator reports runs of pipelines. Each pipeline writes assets. Expectations describe when and how those assets should look. Lineage connects the assets. When an expectation is missed, an alert opens, carries its impact from lineage, and goes to the owner.