maiven gateway · online··
manifest · 1d ago
Sign in
data docs

Reader-friendly documentation

Every documented model, source, and metric in the MAIVEN project — written for the people who query the data, not just the people who build it. Searchable, filterable, and stable-linked.

manifest 1d ago·last build 1d ago
documented
299
certified
258%
with context
27692%
with PII
77
columns
3,451
299 of 299
fullPII hiddenrows filteredblocked
mart

Answer-shaped tables

48 entries

The wide, certified tables analysts query and BI tools point at. Each mart answers a clear business question ("who are our customers?", "how did support do last week?"). Contracts are enforced; column types are stable.

Ap Aging

marts.mart_ap_aging
martbetabuild 1d agotests 13/13 passingfinance-analytics@example.com

Open AP per vendor bill, aged into buckets.

One row per open vendor bill as of the snapshot day, with the vendor, remaining functional-USD balance, days overdue from due_date, and aging bucket (current / 1_30 / 31_60 / 61_90 / 90_plus). Total open AP ties to the AP control account (subledger_ties_to_gl).

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highSumming base_total_amount instead of open_amount

    `base_total_amount` is the original bill total; `open_amount` is the remaining unpaid balance. Aging is about what is still owed — always sum `open_amount`.

  • mediumComparing aging across different as_of_day snapshots

    Buckets are computed relative to a single snapshot day. Mixing rows from different `as_of_day` values double-counts and mis-ages.

Questions this answers
  • “Which vendors have the most past-due AP?”
  • “What is our total open AP right now?”
Related metrics
  • ap_aging

    The de-identified bucket aggregate of this snapshot.

Ap Aging Daily

marts.mart_ap_aging_daily
martbetabuild 1d agotests 7/7 passingfinance-analytics@example.com

Open AP totals by aging bucket and vendor segment.

De-identified rollup of open AP by (as_of_day × aging_bucket × vendor_segment). vendor_segment is the vendor's payment_terms (a coarse, non-identifying class), not the vendor itself. `open_amount` is summed functional USD; `vendors_count` is a distinct vendor count.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highMixing as_of_day snapshots

    Each `as_of_day` is a full snapshot. Summing across snapshots double-counts the same open balance.

  • mediumReading vendors_count as additive across buckets

    `vendors_count` is a distinct count per bucket — a vendor with bills in two buckets counts in each. Summing across buckets over-counts distinct vendors.

Questions this answers
  • “How much AP is more than 90 days overdue?”
  • “Open AP by aging bucket for the latest snapshot.”
Related metrics
  • ap_aging

    The metric-layer surface over this aggregate.

6 of 6
Column
Type
Description
Tests · PII
as_of_day
Date
Snapshot day. Date. Part of the grain.
1 test
aging_bucket
String
current / 1_30 / 31_60 / 61_90 / 90_plus. Part of the grain.
2 tests
vendor_segment
String
Vendor payment-terms class (coarse, non-identifying). `unknown` when unmapped. Part of the grain.
1 test
open_bills
UInt64
Count of open bills in the bucket. UInt64.
1 test
vendors_count
UInt64
Distinct vendors in the bucket. UInt64.
1 test
open_amount
Decimal(18, 2)
Sum of open functional-USD balance in the bucket. Decimal(18,2).
1 test

Approval Rules

marts.mart_approval_rules
martbetabuild 1d agotests 16/16 passingdata-eng@example.com

The approval-workflow rules that gate proposals — what triggers a sign-off, who signs, and the SLA.

One row per approval rule (grain `rule_id`), sourced from `stg_gcs__rfx_approval_rules`. Each row describes one gate in the proposal-approval chain: `trigger_type` is what it fires on (`discount_pct` / `deal_value` / `margin_floor` / `legal_terms`), `threshold_value` + `comparator` (`gt` / `gte` / `lt` / `lte`) form the condition, `approver_role` is who must approve when it fires, `sequence` orders the rule in the chain, `escalation_role` + `sla_hours` define the escalation if the SLA is breached, and `active` flags whether the rule is currently in force. Reference / governance data — no personal data. Use it to answer "what discount triggers exec approval" or "what is the approval chain for a large deal".

betaexpertdata-eng@example.comlast reviewed2026-06-29
Watch out for
  • highReading inactive rules as the live policy

    `active = 0` rules are retained for history but are NOT in force. Filter `active = 1` before answering "what is the approval policy", or you may surface a superseded threshold.

  • highComparing threshold_value across trigger_types

    `threshold_value` is denominated by `trigger_type` — a `discount_pct` threshold is a percentage, a `deal_value` threshold is a currency amount, a `margin_floor` is a percentage. Comparing or sorting thresholds across mixed trigger_types is meaningless; filter to one `trigger_type` first.

Questions this answers
  • “What discount percentage triggers executive approval?”
  • “What is the approval chain for a high-value deal, in order?”
  • “Which rules escalate to legal, and on what SLA?”

Ar Aging

marts.mart_ar_aging
martbetabuild 1d agotests 13/13 passing1 PII columnfinance-analytics@example.com

Open AR per customer invoice, aged into buckets.

One row per open customer invoice as of the snapshot day, with the customer, remaining functional-USD balance, days overdue from due_date, and aging bucket. Total open AR ties to the AR control account (subledger_ties_to_gl).

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highSumming base_total_amount instead of open_amount

    `open_amount` is the remaining unreceived balance; `base_total_amount` is the original invoice total. Aging is about what is still owed.

  • mediumReading email from an AI persona

    `email` is PII and hidden from AI personas via column grants; this mart is controller/executive-only at the row level anyway.

Questions this answers
  • “Which customers have the most past-due AR?”
  • “What is our total open AR right now?”
Related metrics
  • ar_aging

    The de-identified bucket aggregate (includes DSO).

Ar Aging Daily

marts.mart_ar_aging_daily
martbetabuild 1d agotests 7/7 passingfinance-analytics@example.com

Open AR totals by aging bucket and customer segment.

De-identified rollup of open AR by (as_of_day × aging_bucket × customer_segment). customer_segment is the coarse ecommerce segment, not a customer identifier. `open_amount` is summed functional USD; `customers_count` is a distinct count.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highMixing as_of_day snapshots

    Each `as_of_day` is a full snapshot; summing across snapshots double-counts the same open balance.

  • mediumReading customers_count as additive across buckets

    `customers_count` is distinct per bucket — a customer with invoices in two buckets counts in each. Summing over-counts distinct customers.

Questions this answers
  • “How much AR is more than 90 days overdue?”
  • “Open AR by segment for the latest snapshot.”
Related metrics
  • ar_aging

    The metric-layer surface over this aggregate (includes DSO).

6 of 6
Column
Type
Description
Tests · PII
as_of_day
Date
Snapshot day. Date. Part of the grain.
1 test
aging_bucket
String
current / 1_30 / 31_60 / 61_90 / 90_plus. Part of the grain.
2 tests
customer_segment
String
Customer segment — consumer / business / enterprise / unknown. Part of the grain.
1 test
open_invoices
UInt64
Count of open invoices in the bucket. UInt64.
1 test
customers_count
UInt64
Distinct customers in the bucket. UInt64.
1 test
open_amount
Decimal(18, 2)
Sum of open functional-USD balance in the bucket. Decimal(18,2).
1 test

Budget Vs Actual

marts.mart_budget_vs_actual
martbetabuild 1d agotests 6/6 passingfinance-analytics@example.com

Budget vs posted actual, by account, cost center, and period.

One row per (period × cost_center × gl_account) with the approved `budget_amount`, the posted `actual_amount` (sum(debit) - sum(credit) from the trial balance), and `variance_amount` (actual - budget). FULL JOIN so budget-only and actual-only cells both appear.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highReading variance sign without account context

    `variance_amount = actual - budget`. On expense accounts positive is overspend; on revenue accounts positive is favourable. Always read the sign relative to `account_type`.

  • mediumExpecting budget for every account

    Only budgeted (period × cost_center × account) cells carry a non-zero `budget_amount`; un-budgeted actuals show budget 0 and a full-amount variance. That is by design (FULL JOIN), not a bug.

Questions this answers
  • “Which cost centers are over budget this period?”
  • “Largest budget variances by account this quarter.”
Related metrics

Cash Position

marts.mart_cash_position
martbetabuild 1d agotests 6/6 passingfinance-analytics@example.com

Daily cash in/out and running balance per bank account.

One row per (as_of_day × bank_account) from bank transactions: credit increases cash, debit decreases it. `net_flow` is the day's credit - debit; `running_balance` is the cumulative balance through the day per account (the latest row per account is the current balance). A cash snapshot, not a full cash-flow-statement categorization.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
Watch out for
  • highSumming running_balance across days

    `running_balance` is already cumulative. Summing it across days compounds the balance nonsensically — pick the latest day per account instead.

  • mediumMixing currencies across accounts

    Each bank account carries its own `currency` (USD, EUR). Summing `running_balance` across accounts of different currencies mixes units; convert or group by currency first.

Questions this answers
  • “What is our current cash balance per bank account?”
  • “How did cash move last month for the US operating account?”
Related metrics

Client Scorecard

marts.mart_client_scorecard
martbetabuild 1d agotests 3/3 passingdata-eng@example.com

Per-client×contract SLA scorecard — OTIF and pick-accuracy actual vs target, volume, and billing.

One row per client×contract engagement (grain (client_id, contract_id)), sourced from int_whse__contract_sla joined to fulfillment actuals. Carries each SLA target next to its achieved actual (otif_target_pct/otif_actual_pct, pick_accuracy_target_pct/ pick_accuracy_actual_pct, dock_to_stock_target_hrs), the derived otif_gap_pct (negative = breach), order_volume, billing_model (∈ {open_book, fixed_fee, cost_plus, activity_based}), and client segment/tier. client_name is a company, not PII. Client-scoped via the client_account_manager row policy on client_id — the canonical isolation-demo surface: two managers open this and see disjoint scorecards.

betaexpertdata-eng@example.comlast reviewed2026-07-01
Watch out for
  • highComparing actual to target without the gap sign

    A breach is otif_actual_pct < otif_target_pct (i.e. otif_gap_pct < 0) — read the sign, don't assume higher-is-worse.

  • highAssuming a manager sees every client

    The row policy scopes to the caller's client_id. This mart is the isolation showpiece — disjoint rows per manager are the expected, enforced behavior.

  • lowReading client_name as PII

    A client is a company; the natural-person PII (primary_contact_name/email) is not projected here.

Questions this answers
  • “Which of my contracts are breaching OTIF?”
  • “Show strategic-tier clients under an activity-based billing model.”
  • “List active contracts by achieved OTIF.”

Customer Support Health

marts.mart_customer_support_health
martcertifiedbuild 1d agotests 8/8 passing1 PII columncs-analytics@example.com

Who are our customers right now, and which ones are at risk.

Point-in-time view of every customer with a derived health flag. Joins lifetime revenue (from mart_customers) with support footprint (tickets, resolution, CSAT). `at_risk` fires on any of: CSAT ≤ 2.5, ≥3 currently-open tickets, or ≥5 lifetime high-priority tickets. Snapshot — not a time series.

certifiedexpertcs-analytics@example.comlast reviewed2026-05-19
What it means
Watch out for
  • highTreating the heuristic as a model output

    `health_segment` is a hand-tuned rule, not a prediction. Reasoning about churn risk over time requires a real model; this flag is a triage signal.

  • mediumFiltering on PII columns from AI personas

    `email` is excluded from AI personas via column grants and is not declared as a filter on this metric — filtering on it returns 400. Row-level access is gated by row policies (e.g. region_us_analyst sees only country='US').

  • mediumUsing this metric for a trend

    Snapshot only. For trend, pair with `revenue` + `support_volume` and read the moving picture from the time-grained metrics.

Questions this answers
  • “How many at-risk customers do we have in the US?”
  • “At-risk share by segment.”
  • “Average lifetime revenue for enterprise customers signed up after 2024.”
Related metrics
  • revenue

    Trend view of the revenue that this snapshot rolls up per-customer. Pair when answering "is at-risk share growing faster than revenue?"

  • support_volume

    Queue-side input that feeds the at-risk heuristic.

  • consent_state

    DPO-only — pair to answer "do at-risk customers still have active marketing consent?"

Customers

marts.mart_customers
martcertifiedbuild 1d agotests 4/4 passing1 PII columnanalytics@example.com

Every customer with their lifetime order rollup.

One row per customer carrying lifetime order count, lifetime revenue, and first/last order timestamps. The customer-keyed input to `mart_customer_support_health` and to per-customer queries. PII (email) is masked out for AI personas via column grants — row-level access is gated by row policies (e.g. `region_us_analyst` sees only `country='US'`).

certifiedexpertanalytics@example.comlast reviewed2026-05-19
Watch out for
  • mediumCounting rows here for "distinct customers"

    This mart is one row per customer, so a naive COUNT over a filtered window double-counts nothing — but a multi-bucket metric query should use `customer_health.customers_count` (uniqExact) instead of summing row counts.

  • mediumReading `email` from an AI persona

    `email` is PII and excluded from `bi_reader` / `ai_readonly` via column grants. A query that selects it as those personas returns a permission error, not a null.

Questions this answers
  • “How many customers are in each segment?”
  • “Who are the highest lifetime-revenue customers in the US?”

Document Chunks

marts.mart_document_chunks
martbuild skippedtests 6 declared2 PII columnsdata-eng@example.com

Embedded chunks — the semantic-search surface.

One row per chunk with an `embedding Array(Float32)` column and a `vector_similarity('hnsw', 'cosineDistance', N)` index. AI reaches this mart only via `search_documents` — never via raw SQL. The `embedding` column is initially `[]`; the embedding worker fills it idempotently.

Watch out for
  • Querying chunks via raw SQL

    There is no raw-SQL surface over this mart for AI. The only path is the gateway's `search_documents` MCP tool, which embeds the query and runs persona-scoped cosineDistance. Direct SELECT on `chunk_text` or `embedding` requires operator credentials.

  • Swapping the embedding model without re-embedding

    The HNSW index is built for `cosineDistance` with a fixed dimension. Swap requires updating both the `EMBEDDING_DIM` env var on the worker AND the `embedding_dim` dbt var, then rebuilding the mart (which drops the old index) and re-running the embedder over every row. Mixed-dim or mixed-model rows break the index silently.

Questions this answers
  • “Find the 10 most relevant chunks about <topic>.”
  • “How many chunks did we produce per document this month?”

Documents

marts.mart_documents
martbuild skippedtests 7 declared2 PII columnsdata-eng@example.com

Catalog over our unstructured corpora.

One row per document we've extracted. Use this to look up what we have, what the extractor did to it, and how much PII it likely contains (per the Presidio entity-count summary). The searchable surface is `mart_document_chunks`; this mart is the index of what's been indexed.

Watch out for
  • Treating `pii_entities_json` as PII content

    `pii_entities_json` is a JSON map of entity-type → count (e.g. `{"PERSON": 1, "LOCATION": 4}`). It carries counts only — never the values. Use the metric `documents_by_corpus` for governance-level reasoning; for the actual text reach the chunk via `search_documents`.

Questions this answers
  • “How many documents do we have per corpus this month?”
  • “Which corpus is producing the most distinct PII entity types?”

Finance Communications

marts.mart_finance_communications
martbetabuild 1d agotests 4/4 passing2 PII columnsfinance-analytics@example.com

Email, chat, and notes unified into one searchable comms row.

One row per finance communication (email message, chat message, or finance note) carrying its subject/title and inline body_text, the GCS source_uri / document_id, and the best-effort linked finance entity (from communication_links). The body text + subject are free-text PII; AI reaches the body only via search_documents, never through this raw mart (which is controller/brain-only). This mart is deliberately NOT exposed as a metric — free text never enters the metric layer.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
Watch out for
  • highTrying to reach body_text from an analyst persona or a metric

    body_text + subject are free-text PII. This mart is controller/brain-only and is NOT a metric source. AI reaches the text only via the persona-scoped search_documents tool — never via a metric or a raw analyst read.

  • mediumTreating a missing entity link as no relationship

    `linked_entity_*` is the single best-effort link per communication (lowest link id). A communication may carry several links upstream; a null here means none were recorded, not that the comm is unrelated.

Questions this answers
  • “Which communications are linked to a given vendor bill?”
  • “How many chat messages versus emails do we hold for finance?”

Forecast

marts.mart_forecast
martbetabuild 1d agotests 8/8 passingfinance-analytics@example.com

Forecasted amounts by scenario, version, period, and cost center.

One row per (period × cost_center × scenario × version × gl_account) with the forecasted amount and the forecast header (scenario, version, status). Versions are kept side by side so accuracy can be measured against a fixed baseline. The forecast side of forecast-accuracy.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highMixing scenarios or versions in one total

    scenario and version are part of the grain. Summing across them blends base/upside/downside (and re-forecasts) into a meaningless total — always filter to one scenario × version.

  • mediumTreating forecast as actual

    `forecast_amount` is a plan, not posted GL. For accuracy pair it with the posted actual (gl_balances_by_period / budget_vs_actual).

Questions this answers
  • “What is the base-scenario forecast for cost center CC-1000 this year?”
  • “Compare upside vs downside forecast for revenue accounts.”
Related metrics

Fulfillment Daily

marts.mart_fulfillment_daily
martcertifiedbuild 1d agotests 12/12 passingdata-eng@example.com

Daily fulfillment rollup — OTIF, on-time, in-full, and pick-accuracy counts by segment, region, temp class, and carrier.

The pre-aggregated operational-analytics rollup for the 3PL fulfillment domain. One row per (ship_month × client_segment × site_region × temp_class × carrier) carrying raw count columns (never pre-divided rates): order_count, units_shipped, otif_count, on_time_count, in_full_count, accurate_lines, total_lines. Only shipped orders are counted (ship_date is not null), so the counts are correct denominators for on-time/OTIF rates. ship_month is toStartOfMonth(ship_date), so this is a trend surface. It feeds two metrics — fulfillment (OTIF/on-time/in-full rates) and pick_accuracy (accurate_lines/total_lines) — which recompute rates with nullif formula measures so multi-bucket roll-ups stay window-correct. Nullable dims are coalesced to unknown so they stay MergeTree-safe and visible.

certifiedexpertdata-eng@example.comlast reviewed2026-07-01
Watch out for
  • highDividing count columns client-side

    OTIF/pick-accuracy are ratios of two count columns; divide them client-side across buckets and you get a biased average-of-averages. Request the otif_rate / pick_accuracy formula measures — the metric layer applies nullif and re-divides window-correctly.

  • mediumReading a single ship_month as a full-period result

    Grain is keyed on ship_month; sum counts across the relevant month range before dividing, don't read one month in isolation.

  • mediumExpecting per-client rows here

    This rollup is de-identified to segment/region — it carries no client_id. For client-scoped fulfillment use mart_client_scorecard / mart_order_outcomes (both row-policy scoped).

Questions this answers
  • “What was OTIF for life_sciences clients in the EU last quarter?”
  • “How does pick accuracy trend by temp class?”
  • “Which carrier has the best on-time rate for frozen goods?”

Gl Balances

marts.mart_gl_balances
martbetabuild 1d agotests 6/6 passingfinance-analytics@example.com

Posted GL balances by account, period, and cost center.

One row per (period × gl_account × cost_center) summarising posted journal lines. `net_amount` is the balance computed as sum(debit) - sum(credit); the sign follows the account's normal side. Built only from posted entries (drafts/reversed excluded). The starting point for the trial balance and financial statements.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highSumming debit and credit into one number

    The balance is `net = sum(debit) - sum(credit)`, never the sum of both. Adding debit_amount + credit_amount gives total posting volume, not a balance, and will not tie to the trial balance.

  • mediumReading draft or reversed entries here

    This mart is posted-only by construction. Draft / reversed entries never contribute, so a balance here is the standing posted balance, not work-in-progress.

Questions this answers
  • “What is the net balance of the Accounts Receivable control account this period?”
  • “Which cost centers carry the most expense in FY2025-M12?”
Related metrics

Inventory Daily

marts.mart_inventory_daily
martcertifiedbuild 1d agotests 11/11 passingdata-eng@example.com

How much stock sits where, by category.

Per-day inventory rollup by (warehouse, category). Use `unique_skus_below_reorder` for cross-warehouse summaries — averaging `under_reorder_pct` unweighted misleads. Stockouts (`on_hand_qty=0`) are tracked as a count, not a percentage.

certifiedexpertdata-eng@example.comlast reviewed2026-05-20
Watch out for
  • highAveraging `under_reorder_pct` across warehouses unweighted

    Each (product, warehouse) pair has its own reorder point; an average-of-averages weights small warehouses equal to large ones. Use `unique_skus_below_reorder` (a count) for cross-warehouse summaries.

  • highSumming `on_hand_qty` across snapshot dates

    These are point-in-time snapshots; summing across dates double-counts the same inventory. Use a `start_day=end_day` filter for current state, or `avg()` for the period mean.

Questions this answers
  • “How many SKUs are below reorder by warehouse today?”
  • “Stockout count by category over the last 30 days.”
Related metrics
  • revenue

    Stockouts cap revenue — out-of-stock SKUs lose sales.

  • fulfillment_sla

    Inventory location determines transit time.

Inventory Health

marts.mart_inventory_health
martbetabuild 1d agotests 3/3 passingdata-eng@example.com

Per-lot stock health — quantity, days of cover, turnover, and near-expiry, per client.

One row per inventory lot (grain lot_id), sourced from int_whse__inventory_valued. Carries qty_on_hand, derived days_of_cover and turnover_ratio, a near_expiry_flag (computed against the fixed logistics_as_of horizon), storage zone/bin/status, temp_class/ hazard_class, and the client_id / sku / site_id FKs. status ∈ {available, allocated, quarantine, damaged, expired}. This is the per-lot table the inventory_turnover metric aggregates over; read rows to name which lots are slow-moving or near expiry. Client-scoped via the client_account_manager row policy on client_id.

betaexpertdata-eng@example.comlast reviewed2026-07-01
Watch out for
  • highTreating NULL days_of_cover as zero cover

    NULL means no outbound velocity to divide by (dead/new stock), not "sells out today". Treat NULL as "cover undefined", filter explicitly.

  • highAssuming full visibility

    Row policy scopes to the caller's client_id — a client manager sees only their lots.

  • mediumComparing turnover_ratio across temp classes naively

    Frozen vs ambient velocities differ structurally; slice by temp_class before ranking.

Questions this answers
  • “Which lots for this client are near expiry?”
  • “Show slow-moving frozen stock over 90 days of cover.”
  • “List quarantined lots at a site.”

Journal Entries

marts.mart_journal_entries
martbetabuild 1d agotests 5/5 passingfinance-analytics@example.com

Every posted/draft GL line with its entry and account.

One row per journal LINE with the entry header (number, date, source, status, creating employee) and the account it posts to. `net_amount` per line is debit - credit. The drill-down behind the GL balances; the creating employee is an actor reference, not a maskable identity column.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highSumming debit and credit together for a balance

    Per-line `net_amount` is debit - credit. Adding both columns gives gross posting volume, not a balance.

  • mediumTreating created_by_employee_id as a maskable identity column

    It is an actor reference (a DSAR-access location), not the employee identity surface. Employee erasure tokenizes finance_employees, not these retained legal_obligation rows.

Questions this answers
  • “Show the lines of journal entry JE-2025-000123.”
  • “Which entries did a given employee create last period?”
Related metrics

Marketing Engagement Daily

marts.mart_marketing_engagement_daily
martcertifiedbuild 1d agotests 12/12 passingmarketing-eng@example.com

Sends, opens, clicks, unsubs — the funnel.

Daily engagement funnel rollup. Sends are gated upstream on the active marketing-consent state at send-time; mid-window consent withdrawals are NOT reflected here. For real compliance reporting, pair with the `consent_state` metric (built on `mart_consent_current`) rather than reading this surface alone.

certifiedexpertmarketing-eng@example.comlast reviewed2026-05-20
What it means
Watch out for
  • highUsing this surface for compliance reporting

    Consent is only checked at send-time upstream. A customer who withdraws consent after their send appears here as a valid send. For audit, join with `mart_consent_current` to filter to currently-consented recipients.

  • mediumComputing CTR as `clicked / sends`

    CTR is `clicked / delivered` — bounces shouldn't reduce CTR (they never reached the inbox). Use the `ctr` formula measure, not a manual ratio.

Questions this answers
  • “Click-through rate by channel last month.”
  • “Unsubscribe rate by audience segment this quarter.”
Related metrics

Mdt Approval Rules

marts.mart_mdt_approval_rules
martbetabuild skippedtests 2 declareddata-eng@example.com

The rules that route an MDT proposal through review, escalation, and issuance.

One row per routing/approval rule (grain rule_id), grouped by rule_type: escalation_trigger (e.g. high_value at the £250k LOA threshold, new_scope_of_work, unusual_or_high_risk_technical, capex_new_equipment, manual_override), review_path (standard / escalated), issuance_route (uk_front_desk / us_bdm_direct / live_presentation_then_reissue), and requote_reason. sequence_order gives the escalation-ladder / step order.

betaexpertdata-eng@example.comlast reviewed2026-07-04
Watch out for
  • mediumTreating the £250k LOA threshold as final

    threshold_value on the high_value trigger is the MVP placeholder (£250k); Session 3 recorded a £150k–£500k debate. It is not a locked business rule.

  • lowReading rule_type outside the enum

    rule_type is constrained to escalation_trigger / review_path / issuance_route / crm_stage / requote_reason. Filter on those values.

Questions this answers
  • “What triggers an escalated review, and at what value threshold?”
  • “How is a UK-entity proposal routed after approval?”
8 of 8
Column
Type
Description
Tests · PII
rule_id
String
Primary key — grain of this mart.
2 tests
rule_type
Nullable(String)
Rule category (escalation_trigger / review_path / issuance_route / crm_stage / requote_reason).
name
Nullable(String)
Rule name/token (e.g. high_value, standard, uk_front_desk, scope_change).
description
Nullable(String)
What the rule does.
threshold_value
Nullable(Decimal(14, 2))
LOA escalation threshold value (£250k placeholder on high_value), if any.
threshold_currency
Nullable(String)
Threshold currency, if any.
applies_to_entity
String
Entity the rule is scoped to (e.g. smithers_mdt_ltd_uk), or empty for all.
sequence_order
Nullable(UInt8)
Escalation-ladder / step order.

Mdt Historical Matches

marts.mart_mdt_historical_matches
martbetabuild skippedtests 3 declareddata-eng@example.com

Which past jobs are comparable to an opportunity — the grounding for ROM benchmarking.

One row per curated similarity edge (grain match_id) between an opportunity and a precedent job reference, with similarity_score (0–100), a prose relevance_note explaining why the precedent matters (method reuse, same client, overlapping test scope), and referenced_in_rfq marking edges the client's own RFQ cited. matched_proposal_id joins the precedent to its proposal so line-item pricing can be re-aggregated.

betaexpertdata-eng@example.comlast reviewed2026-07-08
Watch out for
  • mediumTreating similarity_score as a model output

    Scores are curated/heuristic (estimator judgement or synthetic generation), not embeddings similarity. Use them to rank, not as calibrated probabilities.

  • mediumAssuming every match resolves to a proposal

    matched_proposal_id is NULL when the precedent reference has no proposal row (e.g. a method-development reference cited in RFQ prose). ROM reconstruction is only possible for non-NULL matches.

Questions this answers
  • “Which past jobs are comparable to this opportunity, strongest first?”
  • “What ROM did the closest comparable carry?”
7 of 7
Column
Type
Description
Tests · PII
match_id
String
Primary key — grain of this mart.
2 tests
opportunity_id
Nullable(String)
The CURRENT opportunity this comparable edge belongs to.
matched_reference_id
Nullable(String)
Job reference of the precedent (may predate the extract window).
matched_proposal_id
String
Proposal of the precedent job, when the reference resolves; NULL otherwise.
similarity_score
Nullable(Decimal(5, 2))
Curated similarity 0–100 (estimator judgement / synthetic heuristic).
relevance_note
Nullable(String)
Why the precedent matters. Confidential-commercial — may name clients.
referenced_in_rfq
UInt8
1 when the client's own RFQ cited this precedent.

Mdt Pipeline

marts.mart_mdt_pipeline
martcertifiedbuild skippedtests 6 declareddata-eng@example.com

Where MDT proposals sit by entity, region, study type, and status over time.

The proposal pipeline rollup for the medical-device testing-services domain. Each row is one (issued_month × entity × client_region × study_type × proposal_status) bucket carrying the proposal count, the summed base ROM (ex-VAT ex-contingency), and the average request→issued cycle time. issued_month is the month the proposal was issued, so this is a trend surface. Proposals without an issued_date (drafts / ROM-only quotes) drop out of the issued-month grain.

certifiedexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • highTreating total_rom_sum as won/booked revenue

    total_rom_sum sums the base ROM across every proposal in the bucket regardless of status — issued, draft, won, lost. It is quoted-pipeline value, not realised revenue. Filter status='won' before reading it as booked.

  • mediumReading a single month as the whole pipeline

    The grain is issued_month; sum across the relevant range rather than reading one month in isolation.

Questions this answers
  • “What is the MDT proposal pipeline value by study type this year?”
  • “How many proposals were issued per month by entity?”
8 of 8
Column
Type
Description
Tests · PII
issued_month
Date
First day of the month the proposal was issued. Sort/partition key.
1 test
entity
String
Issuing Smithers legal entity (or 'unknown').
1 test
client_region
String
Client region (or 'unknown').
1 test
study_type
String
Study type (or 'unknown').
1 test
proposal_status
String
Proposal lifecycle status (or 'unknown').
1 test
proposal_count
UInt64
Count of proposals in the bucket.
1 test
total_rom_sum
Nullable(Decimal(38, 2))
Summed base ROM across proposals in the bucket. Confidential-commercial aggregate.
avg_cycle_time_days
Nullable(Float64)
Mean request→issued cycle time (days) across the bucket.

Mdt Pricing

marts.mart_mdt_pricing
martbetabuild skippedtests 2 declareddata-eng@example.com

Cost line items behind each proposal's ROM (BI-only).

One row per pricing line item (grain line_item_id): device_nickname, category, related_test, quantity/rate/amount, and the proposal currency. The amounts sum to the proposal's total_rom. Confidential-commercial — exposed only to BI + commercial personas.

betaexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • highExposing pricing to AI personas

    amount / rate are confidential-commercial. This mart grants no ai_readonly access and the row-detail is restricted to commercial personas. Do not add ai_readonly to accessible_to.

Questions this answers
  • “How does a proposal's ROM break down by device?”
  • “What are the largest cost line items?”

Mdt Proposals

marts.mart_mdt_proposals
martbetabuild skippedtests 2 declareddata-eng@example.com

Win/loss/status and profile of every MDT proposal.

One row per proposal (grain proposal_id) from int_mdt__proposal_economics. Carries entity, study_type, client_region, proposal_status, currency, the base ROM (total_rom — confidential-commercial), is_won / is_decided flags, review_path, and the request→issued cycle_time_days. Prefer the aggregate metrics for grouped rates; read rows here to inspect individual proposals.

betaexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • highTreating issued proposals as decided

    Most historical proposals are status 'issued' (outcome unknown), not won/lost. is_decided is 1 only for won/lost. Restrict to is_decided=1 before computing a win rate.

  • mediumExpecting total_rom in query_records output

    total_rom is confidential-commercial and is NOT in the proposal row-detail projection. Use the mdt_proposal_economics metric for aggregate ROM; per-line pricing is the BI-only mart_mdt_pricing.

Questions this answers
  • “Which proposals are on the escalated review path?”
  • “What is the win rate by study type?”

Mdt Rate Card

marts.mart_mdt_rate_card
martbetabuild skippedtests 11 declareddata-eng@example.com

Per-test rate card (GBP pence) for costing RFQ test requests.

One row per (related_test, category). related_test is the exact-matchable test name — a canonical test family or one of the raw mdt_test_methods.test_name variants (is_canonical=0 alias). canonical_test is the normalized family. unit_rate_minor is the per-unit rate in GBP integer pence; category splits labour / setup / materials. Synthetic reference data (build_rate_card.py); a few families are anchored to observed proposal pricing, the rest are seed-derived within a plausible band. BI + commercial personas only.

betaexpertdata-eng@example.comlast reviewed2026-07-05
Watch out for
  • highExposing the rate card to AI personas

    unit_rate_minor is confidential-commercial. This mart grants no ai_readonly access and the row-detail is restricted to commercial personas. Do not add ai_readonly to accessible_to.

  • mediumReading unit_rate_minor as pounds

    unit_rate_minor is integer PENCE (420000 = £4,200). Divide by 100 for pounds. This is a deliberate departure from the repo's major-unit Decimal money convention.

  • mediumDouble-counting canonical + alias rows

    A physical test appears as one canonical row (is_canonical=1) plus raw-name alias rows (is_canonical=0) carrying the same rate. Dedupe on canonical_test; prefer canonical rows.

Questions this answers
  • “What's the labour rate for vacuum decay CCIT testing?”
  • “What are the most expensive tests on the rate card?”
8 of 8
Column
Type
Description
Tests · PII
rate_card_id
String
Primary key — grain of this mart (uuid5).
2 tests
related_test
String
Exact-matchable test name — canonical family or raw-name alias.
1 test
canonical_test
String
Normalized test family; aliases of the same physical test share it.
1 test
is_canonical
UInt8
1 = canonical family row, 0 = raw-name alias (same rate).
2 tests
category
String
Cost category — labour / setup / materials.
2 tests
unit_rate_minor
Int64
Per-unit rate in GBP integer pence (420000 = £4,200).
2 tests
currency
String
Always GBP.
1 test
basis
Nullable(String)
Provenance string (anchored / seed-derived / alias of …).

Mdt Rfps

marts.mart_mdt_rfps
martbetabuild skippedtests 2 declareddata-eng@example.com

The incoming RFP intake queue — what's been requested and where it sits.

One row per incoming Request for Proposal (grain rfp_id) in the intake pipeline (MVD Category 02). Real RFPs (grounded in the package RFQ artifacts, linked to their quoted opportunity) plus synthetic net-new prospects. Carries entity/region/channel, requested device/test scope, target dates, and the intake status (received → qualifying → quoted, or declined / on_hold). Use it to reason about the pre-proposal funnel; for issued-proposal outcomes use query_records('mdt_proposal').

betaexpertdata-eng@example.comlast reviewed2026-07-04
Watch out for
  • highTreating RFP count as proposals/opportunities

    An RFP is an incoming request; only those with intake_status='quoted' (is_linked_to_opportunity=1) became a proposal. Don't equate RFP volume with proposal or win counts.

  • mediumExpecting client name / budget here

    client_name and budget_indication are confidential-commercial and are not projected on this mart (they stay in staging).

Questions this answers
  • “Which RFPs are still in the intake queue (received or qualifying)?”
  • “How many incoming RFPs arrived by channel this quarter?”

Mdt Test Plans

marts.mart_mdt_test_plans
martbetabuild skippedtests 2 declareddata-eng@example.com

Devices under test with their test-method rollup.

One row per device (grain device_id): device name/type/manufacturer/ active ingredient/variant count, plus test_count, replicate_total, and the distinct standards cited across its tests, joined to the parent opportunity's entity / study_type / region.

betaexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • mediumTreating replicate_total as sample count

    replicate_total sums replicates_per_variant across the device's tests; it is not the total number of physical samples (which also depends on variant count and destructive/non-destructive reuse).

Questions this answers
  • “Which autoinjector devices have the most tests?”
  • “What standards apply to a given device?”

Month End Close

marts.mart_month_end_close
martbetabuild 1d agotests 5/5 passingfinance-analytics@example.com

The close checklist, one row per period and step.

One row per (period × close_step) exploding the close rollup into the controller's checklist: post_all_entries, trial_balance_ties, reconcile_bank, lock_period. `step_status` is done / pending / blocked, backed by the entry, trial-balance, and reconciliation counts.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • mediumReading trial_balance_ties without the period grain

    `trial_balance_ties` is per period. The same flag repeats on every step row for that period — dedupe to one row per period before counting tied periods.

  • mediumTreating step_status='pending' as failure

    `pending` means the step is simply not yet done (e.g. no reconciliations opened). Only `blocked` signals an upstream condition is failing (drafts still open).

Questions this answers
  • “Which periods still have draft entries blocking the close?”
  • “Show the close checklist for FY2025-M12.”
Related metrics

Order Outcomes

marts.mart_order_outcomes
martbetabuild 1d agotests 3/3 passingdata-eng@example.com

Win/loss of the SLA promise for every order — OTIF, cycle time, line accuracy, and value, per client.

One row per order (grain order_id), sourced from int_whse__order_enriched. Carries the SLA outcome trio (is_otif / is_on_time / is_in_full), cycle_time_hrs (order→ship), line_accuracy_pct, order_value, and the client_id / site_id / consignee_id FKs. De-identified — consignee_id is a surrogate, never the recipient's name/address/email. This is the per-order table the fulfillment metric aggregates over; read rows here (via query_records('fulfillment_order')) to name which orders breached SLA. Client-scoped: the client_account_manager row policy restricts rows to the caller's assigned client_id.

betaexpertdata-eng@example.comlast reviewed2026-07-01
Watch out for
  • highReading open orders as SLA failures

    Open orders have NULL ship_date / is_otif / cycle_time_hrs. Filter ship_date IS NOT NULL (or is_otif IN (0,1)) before treating a row as a decided outcome.

  • highAssuming a manager sees all orders

    Row policy silently scopes to the caller's client_id — two client managers get disjoint, non-empty row sets; ops/compliance/AI personas see all. A "missing" order is usually a tenant-scope boundary, not absent data.

  • mediumAggregating rates from rows instead of the metric

    For OTIF/accuracy rollups use the fulfillment / pick_accuracy metrics; these rows are for naming individual orders, not window-correct rates.

Questions this answers
  • “Which orders for this client breached SLA in June, and what was the pick accuracy?”
  • “List the slowest-cycle orders shipped last month.”
  • “Show high-value late orders for chilled goods.”

Orders Daily

marts.mart_orders_daily
martcertifiedbuild 1d agotests 5/5 passinganalytics@example.com

How much paid order volume did we book, by when / where / who.

Completed-order revenue, aggregated daily by customer segment and country. "Revenue-eligible" excludes orders in cancelled or refunded status — the same definition Finance uses for the monthly GMV report. AOV is exposed as a formula measure so callers don't recompute it from a multi-bucket window (sum-of-averages bias).

certifiedexpertanalytics@example.comlast reviewed2026-05-19
What it means
Watch out for
  • highRecomputing AOV from a multi-bucket result

    `avg_order_value` is a formula measure (sum(revenue) / sum(paid_orders_count)) — correct under any GROUP BY. Dividing two already-aggregated columns client-side yields a different number when the buckets have unequal sizes.

  • highTreating `unique_customers_daily` as distinct over a window

    It is a SUM of per-day distinct counts — a customer who orders on three days contributes 3. For true distinct-over-window, use the `customer_health` metric's `customers_count` measure.

  • mediumMixing `orders_count` with `revenue` filters

    `orders_count` includes cancelled + refunded; `revenue` and `paid_orders_count` exclude them. Picking the wrong pair inflates conversion / AOV ratios.

Questions this answers
  • “What was revenue last month, broken down by segment?”
  • “Top 5 countries by revenue this quarter, vs last year.”
  • “AOV trend for enterprise customers over the last 8 weeks.”
Related metrics
  • customer_health

    Per-customer snapshot — answers "who drove the revenue number" and gives a true distinct customer count.

  • support_volume

    Cost-side counterpart. Use together when answering "are sales coming with extra support load?"

  • product_reviews

    Quality leading indicator — drift here often precedes revenue softness.

Reconciles with
  • Finance GMV report (monthly close)
    last verified · 2026-04-30drift · 0.40%
7 of 7
Column
Type
Description
Tests · PII
order_day
Date
Calendar date of the orders. Part of the sort/partition key.
1 test
customer_segment
String
Customer segment at order time. `unknown` when the customer row was unavailable.
customer_country
String
ISO-2 customer country at order time. `unknown` when the customer row was unavailable. Drives the `region_us_analyst` row policy.
orders_count
UInt64
Total order rows in the bucket — includes cancelled / refunded.
paid_orders_count
UInt64
Order rows in the bucket where `is_revenue_order` holds (status not in cancelled/refunded).
revenue
Decimal(14, 2)
Sum of `total_amount` for revenue-eligible orders in the bucket. Decimal(14,2).
2 tests
unique_customers
UInt64
Distinct customer count across all orders in the bucket (including cancelled/refunded — uses `uniqExact` over `customer_id`).

Payments Daily

marts.mart_payments_daily
martcertifiedbuild 1d agotests 12/12 passingdata-eng@example.com

Money in / money back per day, by transaction type and status.

Daily payment-funnel rollup. Naively summing `amount` across `transaction_type` double-counts (auth and capture both carry the order total). Revenue = `captured_amount = sumIf(amount, is_final_capture)`. Refunds and failed auths are tracked separately for funnel diagnostics.

certifiedexpertpayments-eng@example.comlast reviewed2026-05-20
What it means
Watch out for
  • highSumming `gross_amount` across transaction types

    Double-counts revenue — `auth` and `capture` rows both carry the order total. Use `captured_amount` for true revenue.

  • mediumTreating `failure_count` as lost-revenue total

    `failure_count` is a row count, not a dollar figure. Use `failed_amount` for the exposure side; not all failures represent lost revenue (auto-retry recovers many).

Questions this answers
  • “What was captured revenue last month, broken down by transaction status?”
  • “Payment failure rate this week.”
Related metrics
  • revenue

    `captured_amount` reconciles with `revenue` over the same window.

  • customer_health

    Customer-level payment failure influences retention.

References
Reconciles with
  • revenue metric (mart_orders_daily)
    last verified · 2026-05-20drift · 0.00%

Pricing Guardrails

marts.mart_pricing_guardrails
martcertifiedbuild 1d agotests 4/4 passingdata-eng@example.com

The discount / margin guardrails for each SKU in each market.

One row per (sku, region, segment) price-book entry, joined to the product catalogue for product_name, category, and unit_cost. It is the deal desk's pricing envelope: `list_price` is the region/segment-adjusted catalogue price; `floor_price` is the HARD floor a quote must never cross; `unit_cost` is the margin basis; `target_margin_pct` and `max_discount_pct` are the policy bounds; and `margin_headroom_pct = (list_price − floor_price) / list_price · 100` is the maximum discount the floor permits. Snapshot of the current price book — not a time series. Commercially sensitive, but accessible to all RFX personas including AI (ai_readonly / rfx_contributor) per the 2026-06-29 decision to surface pricing to AI assistants.

certifiedexpertdata-eng@example.comlast reviewed2026-06-28
Watch out for
  • highTreating floor_price as a soft target rather than the hard floor

    `floor_price` is the absolute minimum a quote may reach — a quote below it must never be issued. It is NOT a margin target and is NOT equal to cost (it is set ≥ implied cost). Deriving a minimum from `list_price` and `max_discount_pct` and ignoring `floor_price` can produce a quote below the floor. Always clamp at `floor_price`.

  • highAssuming pricing is hidden from AI personas

    As of the 2026-06-29 decision, ai_readonly and rfx_contributor CAN read this mart (incl. floor_price / unit_cost / max_discount_pct) via query_records('price_book'). Pricing is still absent from the metric layer — it reaches AI only as governed row detail, never as free aggregates or raw SQL. Treat the figures as commercially sensitive even though AI can now see them.

  • mediumReading margin_headroom_pct when list_price is missing or zero

    `margin_headroom_pct` is null when `list_price` is null or 0 — there is no defined headroom. Filtering or sorting on it without guarding for null silently drops those rows; treat null as "headroom undefined", not "zero headroom".

Questions this answers
  • “What is the lowest price we can quote this SKU in EMEA for the enterprise segment?”
  • “Which SKUs in NA have less than 10% discount headroom before hitting the floor?”
  • “Show the target margin and discount ceiling for SKU X across all markets.”

Procurement Accounts

marts.mart_procurement_accounts
martbetabuild 1d agotests 15/15 passingdata-eng@example.com

The buying accounts behind the RFX pipeline — who we sell to, sized and segmented.

One row per procurement account (grain `account_id`), sourced from `stg_gcs__rfx_accounts`. Each row carries the company `account_name`; the `industry` vertical (`tech` / `healthcare` / `public_sector` / `finance` / `manufacturing` / `energy` / `retail` / `education`); the sales `region` (`NA` / `EMEA` / `APAC` / `LATAM`); the size `segment` (`enterprise` / `mid` / `smb`); the strategic `tier` (`strategic` / `key` / `standard`); the `annual_revenue_band`; and `created_day`. This is the buyer dimension that the opportunity and proposal grains chain their `segment` / `region` from — read rows here to inspect or rank individual accounts; use `mart_rfx_pipeline` / the `rfx_pipeline` metric for pipeline rollups by segment / region.

betaexpertdata-eng@example.comlast reviewed2026-06-29
Watch out for
  • mediumExpecting pipeline / revenue figures on this mart

    This is a pure dimension — no opportunity counts, deal value, or win metrics. Reading it as a pipeline surface returns account attributes only. Use `mart_rfx_pipeline` / the `rfx_pipeline` metric for pipeline sizing.

  • lowTreating account_name as PII

    `account_name` is a company name, not a natural person, so it is not PII and is fully projectable. Don't suppress it for AI personas — the buyer-side natural-person PII lives on `stg_gcs__rfx_contacts`, which is not exposed here.

Questions this answers
  • “Which strategic enterprise accounts are in EMEA?”
  • “List our public-sector accounts by revenue band.”
  • “How many opportunities does account X have?”
8 of 8
Column
Type
Description
Tests · PII
account_id
String
Primary key — the account's stable id. Matches `stg_gcs__rfx_accounts.account_id`.
3 tests
account_name
Nullable(String)
Company name. Free-text — NOT PII (a company is not a natural person).
1 test
industry
Nullable(String)
Vertical the account operates in.
2 tests
region
Nullable(String)
Sales region — `NA` / `EMEA` / `APAC` / `LATAM`.
2 tests
segment
Nullable(String)
Account size segment — `enterprise` / `mid` / `smb`.
2 tests
tier
Nullable(String)
Strategic importance — `strategic` / `key` / `standard`.
2 tests
annual_revenue_band
Nullable(String)
Bucketed annual revenue band.
2 tests
created_day
Nullable(Date)
Calendar date the account record was created.
1 test

Product Quality

marts.mart_product_quality
martcertifiedbuild 1d agotests 17/17 passinganalytics@example.com

How each product is rated — including the ones nobody reviewed.

Per-product review summary joined to the catalog — total / verified / low / high rating counts, average rating, helpful votes, and a coarse `quality_tier` flag (`needs_attention` / `well_reviewed` / `lightly_reviewed`). Includes un-reviewed products so BI can spot catalog gaps. Snapshot, not a trend — for the moving picture use `mart_product_reviews_daily`.

certifiedexpertanalytics@example.comlast reviewed2026-05-19
Watch out for
  • highReading `avg_rating` for un-reviewed products

    `avg_rating` is null when `total_reviews = 0` — it is NOT zero. Filter `total_reviews > 0` before averaging or you will treat a missing rating as a bad one.

  • mediumUsing this snapshot for a ratings trend

    `mart_product_quality` is a point-in-time per-product summary. For "are ratings drifting over time" use the `product_reviews` metric (`mart_product_reviews_daily`).

Questions this answers
  • “Which products need attention (low ratings, enough reviews)?”
  • “How many catalog products have zero reviews?”

Product Reviews Daily

marts.mart_product_reviews_daily
martcertifiedbuild 1d agotests 12/12 passinganalytics@example.com

Are review trends drifting, by category.

Daily review volume and average rating bucketed by product category × verified-purchase. The trend surface for quality — spikes in `low_rating_count` here often precede a category support spike. For per-product accurate averages use `mart_product_quality` (avoids the avg-of-averages bias on `avg_rating` across uneven buckets).

certifiedexpertanalytics@example.comlast reviewed2026-05-19
Watch out for
  • highReading `avg_rating` as an accurate per-product average

    Here `avg_rating` is an avg-of-daily-averages — biased when daily bucket sizes differ. For exact per-product averages use the `product_quality` metric (one row per product).

  • mediumTreating `distinct_reviewers` as unique-over-the-window

    `distinct_reviewers_daily` SUMs per-day distinct counts — a reviewer active on three days counts 3. There is no true distinct-over-window measure on this trend surface.

Questions this answers
  • “Are review ratings drifting by category over the last quarter?”
  • “Verified vs anonymous review share this month.”

Promotion Performance

marts.mart_promotion_performance
martcertifiedbuild 1d agotests 15/15 passingmarketing-eng@example.com

How well are promo codes performing.

Per-day promo rollup. `total_discount` is the realised markdown — NOT incremental revenue lift (no counterfactual baseline). `net_order_amount` is gross minus discount, floored at 0. Pair with the `revenue` metric on a matched control window to estimate true lift.

certifiedexpertmarketing-eng@example.comlast reviewed2026-05-20
What it means
Watch out for
  • highTreating `total_discount` as revenue lost

    Discount is the markdown applied; whether the order would have happened without it is a counterfactual question. For incrementality, compare `revenue` between matched windows with and without the promo.

  • mediumMixing `redemptions` with `redemptions_revenue_orders`

    `redemptions` counts all applied promos (including cancelled/refunded orders); `redemptions_revenue_orders` filters to revenue-eligible. The headline rate depends on which denominator you pair with.

Questions this answers
  • “Top 5 promo codes by redemptions last month.”
  • “Discount cost by discount type this quarter.”
Related metrics
  • revenue

    `net_order_amount` ties back to `revenue` over the same window.

  • customer_health

    Promo redeemers often differ in retention curve.

Proposal Outcomes

marts.mart_proposal_outcomes
martbetabuild 1d agotests 4/4 passingdata-eng@example.com

Win/loss outcome and economics of every submitted proposal.

One row per submitted proposal (grain `proposal_id`), sourced from `int_rfx__proposal_economics`. Each row carries the deal's `segment` (off the account), `region` and `rfx_type` (off the opportunity); the `outcome` (`won` / `lost` / `pending` / `withdrawn`) and the derived `is_won = (outcome = 'won')`; the `total_price` / `total_cost` / `margin_pct` trio ((price − cost) / price · 100); the decision `cycle_time_days` (`decision_date − submitted_date`); and both the `submitted_date` and `decision_date`. `decision_date` and `cycle_time_days` are Nullable and NULL while a proposal is still `pending`. This is the per-entity outcomes table that the `proposal_win_rate` and `proposal_economics` metrics aggregate over — prefer those metrics for grouped counts/rates; read rows here when you need to inspect or rank individual proposals.

betaexpertdata-eng@example.comlast reviewed2026-06-28
Watch out for
  • highTreating pending proposals as losses in a win-rate calc

    `outcome` includes `pending` and `withdrawn`, not just won/lost. Computing win rate as won / total rows understates the rate by counting undecided deals in the denominator. Restrict to `outcome IN ('won','lost')` (what the `proposal_win_rate` metric's decided_count does) before dividing.

  • mediumAggregating cycle_time_days without filtering pending rows

    `decision_date` and `cycle_time_days` are NULL while a proposal is `pending`. avg() skips NULLs (fine), but a COUNT over cycle_time_days or a naive coalesce-to-0 silently includes / zero-fills undecided deals and biases the average down.

  • mediumSumming total_price across all rows as "pipeline value"

    This table is submitted proposals (which can be lost or pending), not the open pipeline. For pipeline sizing use `mart_rfx_pipeline` / the `rfx_pipeline` metric. Here, summing `total_price` over `is_won = 1` gives won bookings, not pipeline.

Questions this answers
  • “What is the win rate for enterprise RFPs in EMEA?”
  • “Which won proposals had the longest decision cycle time?”
  • “What is the average margin on lost deals by segment?”

Returns

marts.mart_returns
martbetabuild 1d agotests 13/13 passingdata-eng@example.com

Per-return case — disposition, reason, processing cycle time, and value, per client.

One row per return (grain return_id). Carries disposition (restock/repair/recycle/scrap), reason (∈ {damaged, wrong_item, late_delivery, no_longer_needed, quality_defect}), cycle_time_days, units_returned, return_value, the parent order_id/site_id, and client_id. This is the per-return table the returns_rate metric aggregates over; read rows to name which returns and why. Client-scoped via the client_account_manager row policy on client_id. reason is a controlled enum, not free text — return narratives are not exposed here (that stays out of the structured layer entirely).

betaexpertdata-eng@example.comlast reviewed2026-07-01
Watch out for
  • highReading a return count as a return rate

    These are raw return rows — a rate needs a shipped-order denominator. Use the returns_rate metric for the rate.

  • highAssuming full visibility

    Row policy scopes to the caller's client_id.

  • mediumTreating disposition as reason

    disposition is what happened to the goods (restock/scrap…); reason is why they came back (damaged/wrong_item/late_delivery/ no_longer_needed/quality_defect) — different columns.

Questions this answers
  • “Which returns for this client were scrapped last month?”
  • “List the longest-to-process returns.”
  • “Show damaged-goods returns by site.”

Returns Daily

marts.mart_returns_daily
martcertifiedbuild 1d agotests 10/10 passinganalytics@example.com

Returns and refunded value per day, by category and reason.

The de-identified daily returns view. One row per (return_day, product_category, return_reason). `returns_count` is the number of return *requests*; `refunded_amount` sums money only for returns that reached `refunded` — the two diverge because requests can be pending or rejected. The customer linkage present in `stg_postgres__returns` is dropped here. To compute a return RATE, pair returns_count with order volume from `metric_revenue_by_month` (orders_count) or `mart_orders_daily`.

certifiedexpertanalytics@example.comlast reviewed2026-05-30
Watch out for
  • highTreating `returns_count` as refunds

    `returns_count` counts every return request, including `requested`, `approved`, and `rejected`. Only `refunded_amount` reflects money actually returned. Use refunded_amount for financial leakage, returns_count for operational volume.

  • highComputing a return rate from this mart alone

    This mart has no order/sales denominator. A return RATE needs order volume from `metric_revenue_by_month` (orders_count) or `mart_orders_daily` over the same window — dividing returns_count by anything inside this mart is wrong.

Questions this answers
  • “Which product categories have the most returns this quarter?”
  • “Where is refund money leaking — by category and reason?”
7 of 7
Column
Type
Description
Tests · PII
return_day
Date
Calendar date the return was requested. Sort + partition key.
1 test
product_category
String
Product category of the returned item; `unknown` when unmapped. Sort key.
1 test
return_reason
String
Reason bucket for the return. Sort key.
1 test
returns_count
UInt64
Number of return requests (all statuses) in this bucket.
1 test
units_returned
UInt64
Total units returned (sum of quantity) in this bucket.
1 test
refunded_amount
Decimal(14, 2)
Sum of refund_amount for `refunded` returns only. Decimal(14,2).
2 tests
distinct_orders
UInt64
Distinct orders represented in this bucket (uniqExact).
1 test

Revenue Daily

marts.mart_revenue_daily
martcertifiedbuild 1d agotests 6/6 passinganalytics@example.com

One number per day — how much we booked.

Headline daily revenue view at a single grain (`order_day`). Excludes cancelled and refunded orders, matching the revenue-eligible definition used by every certified metric. De-identified aggregate — pair with `mart_orders_daily` when you need a breakdown by segment or country.

certifiedexpertanalytics@example.comlast reviewed2026-05-19
Watch out for
  • highAsking for a segment / country split here

    This mart is single-grain (order_day only). A by-segment or by-country question must use `mart_orders_daily` — joining or grouping here cannot recover a dimension that was never stored.

  • mediumTreating `revenue_per_customer` as a windowed average

    `revenue_per_customer` is computed per day (`revenue / unique_customers`). Averaging it across days is an avg-of-ratios — recompute from summed `revenue` and a true distinct customer count (`customer_health.customers_count`).

Questions this answers
  • “What was total revenue last week?”
  • “What is the revenue trend over the last 90 days?”
5 of 5
Column
Type
Description
Tests · PII
order_day
Date
Calendar date of revenue-eligible orders. Unique per row.
2 tests
orders_count
UInt64
Count of revenue-eligible orders on this day.
revenue
Decimal(14, 2)
Sum of `total_amount` across revenue-eligible orders on this day. Decimal(14,2).
2 tests
unique_customers
UInt64
Distinct customers placing any order (any status) on this day.
revenue_per_customer
Decimal(14, 2)
Derived — `revenue / unique_customers`. Decimal(14,2). Null when `unique_customers` is 0.

Rfx Pipeline

marts.mart_rfx_pipeline
martcertifiedbuild 1d agotests 9/9 passingdata-eng@example.com

Where deals sit by stage, segment, and region over time.

The open-pipeline rollup for the procurement / RFX-response domain. Each row is one (issued_month × segment × region × stage) bucket carrying the count of opportunities, the sum of their estimated deal value, and the average win probability. `issued_month` is the month an RFX was issued (toStartOfMonth of issued_date), so this is a trend surface — pair the `stage` dimension with it to see how the pipeline moves from `qualifying` through `won` / `lost` / `no_bid`. Nullable segment / region / stage values are coalesced to `unknown` so they remain MergeTree-safe and visible rather than dropped.

certifiedexpertdata-eng@example.comlast reviewed2026-06-28
Watch out for
  • highTreating est_value_sum as won / booked revenue

    est_value_sum sums the ESTIMATED deal size across every opportunity in the bucket regardless of stage — it includes `qualifying`, `in_progress`, `lost`, and `no_bid`. It is a pipeline-coverage figure, not realised revenue. Filter `stage = 'won'` (or read proposal outcomes) before reading it as closed value.

  • mediumAveraging avg_probability across multiple buckets

    avg_probability is a per-bucket average of the UInt8 0..100 probability. Rolling it up across buckets of unequal size is an avg-of-averages — biased. The `rfx_pipeline` metric exposes avg_probability as an avg aggregate so the metric layer recomputes it correctly; do not average the column client-side.

  • mediumReading a single month as the full pipeline

    The grain is keyed on issued_month (when the RFX was issued), not a snapshot date. A deal issued in March that is still `in_progress` lives in March's bucket — sum across the relevant issued_month range to see total open pipeline, don't read one month in isolation.

Questions this answers
  • “What is the open RFX pipeline value by stage this quarter?”
  • “How many RFX opportunities are in each segment, by region?”
  • “Average win probability of in-progress deals over the last 6 months.”
7 of 7
Column
Type
Description
Tests · PII
issued_month
Date
First day of the month the RFX was issued (toStartOfMonth of issued_date). Part of the sort / partition key.
1 test
segment
String
Account segment behind the opportunity — `enterprise`, `mid`, `smb`, or `unknown` when the account row was unavailable.
1 test
region
String
Opportunity region — `NA`, `EMEA`, `APAC`, `LATAM`, or `unknown`.
1 test
stage
String
Pipeline stage — `qualifying`, `in_progress`, `submitted`, `won`, `lost`, `no_bid`, or `unknown`.
1 test
opp_count
UInt64
Count of opportunities in the bucket.
2 tests
est_value_sum
Nullable(Decimal(38, 2))
Sum of estimated deal value (est_value) across opportunities in the bucket. Decimal — pipeline coverage, NOT booked revenue.
2 tests
avg_probability
Nullable(Float64)
Mean win probability (0..100) across opportunities in the bucket, rounded to 2 decimals.
1 test

Shipments Daily

marts.mart_shipments_daily
martcertifiedbuild 1d agotests 12/12 passingdata-eng@example.com

How quickly do parcels reach customers, by carrier.

Daily aggregate of shipments with SLA outcomes. `on_time_count` requires `delivered_at IS NOT NULL` AND `estimated_delivery_at IS NOT NULL` — in-flight or no-ETA shipments don't contribute to on-time rate. `avg_transit_hours` is the post-pickup time; `avg_ship_lag_hours` is order-to-label.

certifiedexpertfulfillment-eng@example.comlast reviewed2026-05-20
What it means
Watch out for
  • highTreating `on_time_count / shipment_count` as the on-time rate

    Denominator must be `delivered_count`, not `shipment_count` — in-flight shipments haven't been scored yet. Use the `on_time_delivery_rate` formula measure.

  • lowExcluding `label_created` from the surface

    Label-only rows have `shipped_day` coalesced to 1970-01-01 so they remain MergeTree-safe. Filter `shipped_day > '2000-01-01'` for hot-data analysis.

Questions this answers
  • “On-time delivery rate by carrier last month.”
  • “Average transit hours by service level over the last quarter.”
Related metrics
  • support_volume

    Returns and lost parcels drive support tickets.

  • revenue

    Fulfillment failures correlate with refunds.

References

Site Performance

marts.mart_site_performance
martbetabuild 1d agotests 4/4 passingdata-eng@example.com

Per-site operational scorecard — utilization, throughput, labor productivity, and certifications.

One row per warehouse site (grain site_id). Carries utilization_pct (occupied/capacity), throughput_units, order_count, avg_units_per_labor_hr, and the certification flags (cert_gdp / cert_iso27001 / cert_hazmat). A site is shared infrastructure across many tenants, so this mart is intentionally not client-scoped — all personas see all sites. Measures are only tenant-safe for multi_user sites; a dedicated/in_house site's throughput is effectively one client's figure. Feeds the inventory_turnover metric's utilization_pct dimension context; read rows to answer "which sites are hot / cold / certified".

betaexpertdata-eng@example.comlast reviewed2026-07-01
Watch out for
  • mediumReading utilization_pct as a client figure

    Utilization is site-wide across all tenants stored there — it is not attributable to one client (and dedicated-site measures are effectively one client's).

  • lowTreating NULL utilization as 0%

    NULL means capacity or occupancy is unmapped, not empty.

Questions this answers
  • “Which sites are over 90% utilization?”
  • “List GDP-certified sites in the EU.”
  • “Which sites have the best labor productivity?”

Sme Coverage

marts.mart_sme_coverage
martcertifiedbuild 1d agotests 9/9 passing1 PII columndata-eng@example.com

Which experts are loaded into the pipeline, who is available, and who contributes to wins.

Per-SME coverage view. Joins the RFX subject-matter-expert directory (department, title, seniority, region, expertise tags, certifications, weekly capacity, availability) to two pipeline rollups: `assigned_opp_count` (opportunities where the SME is the owner) and `authored_proposal_count` / `won_proposal_count` (proposals where the SME is the lead author, and of those how many had outcome `won`). Use it to answer staffing questions ("who has headroom in EMEA security?") and win-contribution questions ("which authors win the most?"). Snapshot, not a time series. `full_name` is PII (name) and is masked for PII-excluding personas via column grants.

certifiedexpertdata-eng@example.comlast reviewed2026-06-28
Watch out for
  • mediumRanking authors on raw `won_proposal_count`

    `won_proposal_count` is an absolute count, so prolific authors rank highest regardless of quality. For win quality, divide by `authored_proposal_count` (guard against divide-by-zero — it is 0 for SMEs who authored nothing).

  • mediumTreating a zero count as missing data

    `assigned_opp_count`, `authored_proposal_count`, and `won_proposal_count` are coalesced to 0, not null — the mart LEFT-joins from the directory so an SME with no pipeline activity is a real 0, not a gap. Don't filter `IS NOT NULL` to find "active" SMEs; filter `> 0`.

  • mediumReading `full_name` from a PII-excluding persona

    `full_name` is PII and is excluded from `ai_readonly` / `rfx_contributor` via column grants. Selecting it as those personas returns a permission error, not a null. Use `sme_id` as the join/display key for those personas.

Questions this answers
  • “Which available SMEs have security expertise in EMEA?”
  • “Who are the top win-contributing lead authors?”
  • “Which SMEs are loaded into the pipeline but unavailable?”

Subscriptions Monthly

marts.mart_subscriptions_monthly
martcertifiedbuild 1d agotests 10/10 passingdata-eng@example.com

Recurring revenue and churn, monthly.

Per-month rollup of subscription state from the exploding intermediate. `mrr` is `sumIf(monthly_amount, period_status='active')` — annual plans contribute their monthly-normalised value (the source already amortises). New starts and churned events fire only in their exact month, so summing across months is safe.

certifiedexpertrevenue-eng@example.comlast reviewed2026-05-20
What it means
Watch out for
  • highMultiplying `monthly_amount` by 12 for annual plans

    `monthly_amount` is already normalised at the source — annual plans store the per-month value. Sum directly for MRR; multiply only when computing ARR explicitly.

  • highCounting `active_subscriptions` across period_status

    `active_subscriptions` is a row count in the (period_month, plan_name, period_status) bucket — to count truly-active subs in a month, filter `period_status='active'` first.

Questions this answers
  • “MRR by plan over the last 6 months.”
  • “Monthly churn rate this year.”
Related metrics
  • revenue

    MRR is the recurring-revenue subset of total revenue.

  • customer_health

    Subscription churn signals customer churn.

References
8 of 8
Column
Type
Description
Tests · PII
period_month
Date
Start-of-month for this row. Sort + partition key.
1 test
plan_name
String
`monthly` / `quarterly` / `annual`.
1 test
period_status
String
This-month status — `active` / `cancelled` / `expired` / `paused`.
1 test
active_subscriptions
UInt64
Row count of (subscription × month) pairs in the bucket.
2 tests
unique_customers
UInt64
Distinct customer_id count.
1 test
mrr
Decimal(14, 2)
Sum of `monthly_amount` filtered to period_status='active'. Decimal(14,2).
2 tests
new_subscriptions
UInt64
Count of subs that started in this month. Fires once per sub.
1 test
churned_subscriptions
UInt64
Count of subs that cancelled in this month. Fires once per sub.
1 test

Support Tickets Daily

marts.mart_support_tickets_daily
martcertifiedbuild 1d agotests 4/4 passingsupport-analytics@example.com

How loaded is the queue and how fast are we resolving.

Daily support queue health — how many tickets were opened, how many of those got resolved, how long it took, and how customers rated it. Bucketed by category × priority so the ops lead can see which lanes are loaded.

certifiedexpertsupport-analytics@example.comlast reviewed2026-05-19
What it means
Watch out for
  • highAveraging `p50_resolution_hours` across multiple buckets

    Roll-ups of percentiles are biased (avg-of-percentiles). For a true window percentile, query a single-bucket result and read the raw value — don't time_grain over it.

  • mediumReading CSAT without `tickets_with_csat`

    avg_csat_score weights all rated tickets equally per bucket. Always pair it with `tickets_with_csat` so the consumer sees the sample size — buckets with 3 ratings drift wildly.

  • mediumComparing `tickets_closed` to `tickets_opened` across days

    `tickets_closed` counts CURRENT status, not closures-in-bucket. A ticket opened Monday and resolved Tuesday counts in Monday's `tickets_opened` AND `tickets_closed`. close_rate handles this correctly; subtraction does not.

Questions this answers
  • “Which categories had the highest backlog last week?”
  • “CSAT trend for billing tickets, weekly, year-over-year.”
  • “Close-rate by priority, this month.”
Related metrics
  • customer_health

    Per-customer support footprint feeds the at-risk flag. Spikes here drive at_risk_share there.

  • product_reviews

    Negative reviews often precede a category support spike — compare the trends to spot quality regressions early.

  • revenue

    Cross-reference with revenue to answer "is the queue cost catching up with sales growth?"

metric

Governed business measures

22 entries

Named measures and dimensions exposed through the semantic layer. AI agents can only query these (never raw SQL) and humans get the same numbers in Metabase, the catalog, and Slack.

Ap Aging

metrics.metric_ap_aging
metricbetabuild 1d agotests 6/6 passingfinance-analytics@example.com

Open AP totals by aging bucket and vendor segment.

Open accounts-payable totals bucketed by overdue band and vendor payment-terms segment, as of a snapshot day. `open_amount` is the remaining functional-USD balance owed to vendors.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highMixing as_of_day snapshots

    Each as_of_day is a full snapshot of open AP. Summing across snapshots double-counts the same balance — filter to one as_of_day.

  • mediumTreating vendors_count as additive across buckets

    vendors_count is distinct per bucket; a vendor with bills in two buckets counts in each.

Questions this answers
  • “How much AP is more than 90 days overdue?”
  • “Open AP by aging bucket for the latest snapshot.”
Related metrics
  • ar_aging

    The receivables counterpart; pair for a working-capital view.

6 of 6
Column
Type
Description
Tests · PII
as_of_day
Date
Snapshot day. Date. Grain + sort key.
1 test
aging_bucket
String
current / 1_30 / 31_60 / 61_90 / 90_plus. Dimension.
1 test
vendor_segment
String
Vendor payment-terms class (coarse, non-identifying). Dimension.
1 test
open_bills
UInt64
Open bills in the bucket. UInt64.
1 test
vendors_count
UInt64
Distinct vendors in the bucket. UInt64.
1 test
open_amount
Decimal(18, 2)
Open functional-USD balance in the bucket. Decimal(18,2).
1 test

Ar Aging

metrics.metric_ar_aging
metricbetabuild 1d agotests 7/7 passingfinance-analytics@example.com

Open AR totals by aging bucket and customer segment, with DSO.

Open accounts-receivable totals bucketed by overdue band and customer segment, as of a snapshot day, plus a per-segment revenue figure (`revenue_amount`, the invoiced base split across the segment's buckets by open-AR share). `dso` is a formula measure: (open AR / credit sales) × 30 days.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highComputing DSO over a single bucket

    `dso` divides total open AR by credit sales. Filtering to one aging bucket gives a partial-AR DSO, not the headline figure — compute it over all buckets for a segment.

  • highMixing as_of_day snapshots

    Each as_of_day is a full snapshot; summing across snapshots double-counts the same open balance.

Questions this answers
  • “What is DSO by customer segment for the latest snapshot?”
  • “How much AR is more than 90 days overdue?”
Related metrics
  • ap_aging

    The payables counterpart; pair for a working-capital view.

7 of 7
Column
Type
Description
Tests · PII
as_of_day
Date
Snapshot day. Date. Grain + sort key.
1 test
aging_bucket
String
current / 1_30 / 31_60 / 61_90 / 90_plus. Dimension.
1 test
customer_segment
String
Customer segment — consumer / business / enterprise / unknown. Dimension.
1 test
open_invoices
UInt64
Open invoices in the bucket. UInt64.
1 test
customers_count
UInt64
Distinct customers in the bucket. UInt64.
1 test
open_amount
Decimal(18, 2)
Open functional-USD balance in the bucket. Decimal(18,2).
1 test
revenue_amount
Decimal(18, 2)
Segment invoiced base amount, split across buckets by open-AR share (the DSO denominator). Decimal(18,2).
1 test

Budget Vs Actual

metrics.metric_budget_vs_actual
metricbetabuild 1d agotests 7/7 passingfinance-analytics@example.com

Budget vs posted actual and variance, by period and account type.

Monthly budget, actual (posted GL net), and variance (actual - budget) rolled up by account type and cost-center region. `variance_pct` is a formula measure (sum(variance) / sum(budget)) so it stays correct across any window.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highReading variance sign without account context

    variance = actual - budget. On expense accounts positive is overspend; on revenue accounts positive is favourable. Read the sign relative to account_type.

  • mediumRecomputing variance_pct client-side

    variance_pct is a formula measure (sum(variance) / sum(budget)). Dividing already-aggregated outputs across a window biases the result.

Questions this answers
  • “What is the budget variance by account type this quarter?”
  • “Variance percentage by region this year.”
Related metrics
7 of 7
Column
Type
Description
Tests · PII
period_month_start
Date
Month bucket — toStartOfMonth(period start). Grain + sort key.
1 test
account_type
String
asset / liability / equity / revenue / expense; `unknown` when unset. Dimension.
1 test
cost_center_region
String
Cost-center region; `unknown` when unset. Dimension.
1 test
budget_amount
Decimal(18, 2)
Summed approved budget. Decimal(18,2).
1 test
actual_amount
Decimal(18, 2)
Summed posted GL actual (debit - credit). Decimal(18,2).
1 test
variance_amount
Decimal(18, 2)
actual - budget. Decimal(18,2).
1 test
cell_count
UInt64
Number of (cost_center × account) cells in the bucket. UInt64.
1 test

Cash Position

metrics.metric_cash_position
metricbetabuild 1d agotests 9/9 passingfinance-analytics@example.com

Daily cash in / out / net flow and running balance by currency.

Daily cash movement and running balance rolled up by currency and region. running_balance is already cumulative per account, so read it on the latest as_of_day rather than summing over days.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
Watch out for
  • highSumming running_balance across days

    running_balance is already cumulative; summing it across days compounds nonsensically. Read the latest as_of_day instead.

  • mediumMixing currencies

    Balances are per currency (USD / EUR). Summing running_balance across currencies mixes units; group by currency first.

Questions this answers
  • “What is the current cash balance by currency?”
  • “Net cash flow last month.”

Documents By Corpus

metrics.metric_documents_by_corpus
metricbetabuild skippedtests 5 declareddata-eng@example.com

How big is each unstructured corpus, and what did Docling find?

One row per (extraction-day × corpus × pipeline × doc_lang) summarising the unstructured zone. Use this metric to answer "how many documents do we have per corpus?", "is the VLM path producing as many chunks as EasyOCR?", "which corpus is surfacing the most distinct PII entity types?" — without touching chunk text. For the actual text you want, call `search_documents` instead.

betaexpertdata-eng@example.comlast reviewed2026-05-25
Watch out for
  • Reading `chunk_text_bytes_total` as a quality signal

    `chunk_text_bytes_total` sums `length(chunk_text)` across the included chunks — it's a corpus-SIZE proxy. A long invoice line-items table inflates it without saying anything about extraction quality. Use `avg_chunks_per_document` and the `documents_with_chunks` / `documents_count` fraction for quality signals.

  • Treating `pii_entity_kinds_total` as a PII occurrence count

    `pii_entity_kinds_total` SUMs distinct-entity-type counts per document, not occurrences. Two documents each tagged `{PERSON, LOCATION}` contribute 4, not 2 — the *kinds* are counted, not the entities. For an occurrence-level view you would need an entity-level mart, which is deliberately not exposed here.

  • Confusing `documents_with_chunks` with data-loss

    `documents_with_chunks` < `documents_count` means the extractor wrote a documents-row but no chunks for some files — typically an empty-template PDF or an extraction regression. It is an extraction-quality signal, not a data-loss signal. The raw zone still has the file.

Questions this answers
  • “How many documents do we have in each corpus today?”
  • “Which corpus produced the most chunks per document on average?”
  • “Are we extracting more pages via vlm or ocr-easyocr?”
  • “Which corpus is surfacing the most distinct PII entity types?”

Forecast Accuracy

metrics.metric_forecast_accuracy
metricbetabuild 1d agotests 7/7 passingfinance-analytics@example.com

Forecast vs posted actual, with accuracy, by period and scenario.

Monthly forecasted amount vs posted GL actual by scenario and account type. error = forecast - actual; `accuracy_pct` is a formula measure (1 - sum(abs error) / abs(sum(actual))) so it stays window-correct.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highComparing scenarios as if one is the truth

    scenario (base / upside / downside) are alternative plans. Pick one scenario before judging accuracy; blending them is meaningless.

  • mediumRecomputing accuracy_pct client-side

    accuracy_pct is a formula over summed absolute error and actual. Dividing pre-aggregated outputs across a window biases it.

Questions this answers
  • “How accurate was the base forecast by account type this year?”
  • “Forecast error by scenario last quarter.”
Related metrics
7 of 7
Column
Type
Description
Tests · PII
period_month_start
Date
Month bucket — toStartOfMonth(period start). Grain + sort key.
1 test
scenario
String
base / upside / downside. Dimension + sort key.
1 test
account_type
String
asset / liability / equity / revenue / expense; `unknown` when unset. Dimension.
1 test
forecast_amount
Decimal(18, 2)
Summed forecasted amount. Decimal(18,2).
1 test
actual_amount
Decimal(18, 2)
Summed posted GL actual. Decimal(18,2).
1 test
error_amount
Decimal(18, 2)
forecast - actual. Decimal(18,2).
1 test
abs_error_amount
Decimal(18, 2)
abs(forecast - actual). Decimal(18,2).
1 test

Fulfillment

metrics.metric_fulfillment
metricbetabuild 1d agotests 10/10 passinglogistics-analytics@example.com

OTIF, on-time, and in-full rates by segment, region, temp class, and carrier over time.

The certified fulfillment-performance metric for the 3PL warehousing domain. One row per (ship_month × client_segment × site_region × temp_class × carrier) carrying raw COUNT columns — `order_count`, `units_shipped`, `otif_count`, `on_time_count`, `in_full_count` — never pre-divided rates. `ship_month` is `toStartOfMonth(ship_date)` over shipped orders only, so it is a trend surface and the counts are correct denominators for on-time / OTIF rates. The metric layer exposes `otif_rate` / `on_time_rate` / `in_full_rate` as FORMULA measures (count / nullif(sum(order_count), 0)) so multi-bucket roll-ups recompute correctly rather than averaging pre-averaged percentages. Nullable dims are coalesced to `unknown` upstream so they stay visible rather than dropped.

betaexpertlogistics-analytics@example.comlast reviewed2026-07-01
Watch out for
  • highTreating a count measure as a rate

    `otif_count` / `on_time_count` / `in_full_count` are counts, not rates. Request the `otif_rate` / `on_time_rate` / `in_full_rate` formula measures — the metric layer divides by `order_count` with `nullif` window-correctly. Reading a count as a rate is a category error.

  • mediumReading a single month as the full-period rate

    The grain is keyed on `ship_month`. Sum the counts across the relevant month range and let the formula measure divide — dividing per-month pre-aggregated outputs client-side is an average-of-averages, biased across buckets of unequal size.

  • mediumComparing carriers blind to temp class

    Carrier on-time performance varies structurally by `temp_class` (frozen vs ambient lanes differ). Slice by `temp_class` before ranking carriers, or a mix-shift will distort the comparison.

Questions this answers
  • “What was OTIF for life_sciences clients in the EU last quarter?”
  • “Which carrier has the best on-time rate for frozen goods?”
  • “How does in-full rate trend by temp class this year?”
Related metrics
  • pick_accuracy

    Fed by the same `mart_fulfillment_daily` rollup — pairs delivery performance (OTIF / on-time / in-full) with picking quality (accurate lines / total lines) for the same buckets.

  • returns_rate

    Uses this metric's shipped-order count as the denominator for the return rate — pair to read fulfillment quality against downstream returns.

Gl Balances By Period

metrics.metric_gl_balances_by_period
metricbetabuild 1d agotests 8/8 passingfinance-analytics@example.com

Posted GL debit / credit / net by period and account type.

Monthly posted GL balances rolled up by account type / subtype / control flag. `net_amount` is sum(debit) - sum(credit) carried from the mart; the metric layer re-aggregates over the caller's dimensions.

betaexpertfinance-analytics@example.comlast reviewed2026-06-02
What it means
Watch out for
  • highAdding debit_amount and credit_amount for a balance

    The balance is `net_amount = sum(debit) - sum(credit)`, never the sum of both. Use net_amount; the sum of debit + credit is gross posting volume.

Questions this answers
  • “What is the net GL balance by account type this quarter?”
  • “Show debits vs credits for control accounts by month.”
Related metrics

Inventory Turnover

metrics.metric_inventory_turnover
metricbetabuild 1d agotests 4/4 passinglogistics-analytics@example.com

Average inventory turns, days of cover, and site utilization by site, temp class, and segment.

Inventory velocity rolled up from the per-lot `mart_inventory_health` to (inv_month × site × temp_class × client_segment). `inv_month` is `toStartOfMonth(received_date)`. `turnover_ratio` is the average per-lot turnover (units_out_window / avg_qty_on_hand); `days_of_cover` is the average per-lot days of cover; `utilization_pct` is site utilization (occupied ÷ capacity) joined from `mart_site_performance` at the region-level `site` grain — it is SITE-WIDE, not client-specific. All three are `avg()` measures declared Nullable(Float64) (ClickHouse avg-of-Nullable semantics); `avg()` ignores NULLs, so NULL-velocity (dead / new) lots are skipped by construction — do not zero-fill them. The `site` dimension is REGION-LEVEL. De-identified — no lot_id, no client_id.

betaexpertlogistics-analytics@example.comlast reviewed2026-07-01
Watch out for
  • mediumAveraging avg-of-avg across mixed temp classes

    Frozen / chilled / ambient turnover differs structurally. Slice by `temp_class` first; a single blended average across temp classes is an avg-of-averages that hides the mix.

  • mediumReading utilization as client-specific

    `utilization_pct` is SITE-WIDE (occupied ÷ capacity across all tenants stored at the site), joined at the region level. It is not attributable to one client's stock.

  • lowZero-filling NULL turnover / days_of_cover

    `avg()` ignores NULLs, so lots with no outbound velocity (dead / new stock) are skipped by construction — this is correct. Do not zero-fill NULL turnover / days_of_cover; a NULL means "velocity undefined", not "zero turns".

Questions this answers
  • “What is inventory turnover by temp class this year?”
  • “Which regions carry the most days of cover for frozen stock?”
  • “How does turnover compare across segments?”
Related metrics
  • fulfillment

    Turnover measures how fast stock moves; `fulfillment` measures how well orders ship. Pair to read stock velocity against service level for the same region / segment.

7 of 7
Column
Type
Description
Tests · PII
inv_month
Date
First day of the inventory month (toStartOfMonth of received_date). Grain + sort key.
1 test
site
LowCardinality(String)
Region-level site rollup (= `site_region`) — EU / UK / NA / APAC; `unknown` when unmapped. Dimension + sort key.
1 test
temp_class
LowCardinality(String)
Temperature class — ambient / chilled / frozen; `unknown` when unmapped. Dimension + sort key.
1 test
client_segment
LowCardinality(String)
Owning-client segment — automotive / chemicals / fmcg / fashion / high_tech / life_sciences; `unknown` when unmapped. Dimension + sort key.
1 test
turnover_ratio
Nullable(Float64)
Average per-lot turnover ratio (units_out_window / avg_qty_on_hand) in the bucket. Exposed as the `turnover_ratio` measure (avg). Nullable(Float64) because avg() of a Nullable Decimal returns Nullable(Float64); NULL-velocity lots are skipped by avg() (not zero-filled).
days_of_cover
Nullable(Float64)
Average per-lot days of cover (qty_on_hand / avg daily units out) in the bucket. Exposed as the `days_of_cover` measure (avg). Nullable(Float64) — avg() of a Nullable Decimal; NULL when no outbound velocity.
utilization_pct
Nullable(Float64)
Site utilization (occupied ÷ capacity · 100) joined from `mart_site_performance` at the region-level `site` grain — SITE-WIDE context, not client-specific. Exposed as the `utilization_pct` measure (avg). Nullable(Float64) per §0.3 (avg() returns Nullable(Float64), not Decimal).

Mdt Cycle Time

metrics.metric_mdt_cycle_time
metricbetabuild skippedtests 7 declareddata-eng@example.com

Average request→issued cycle time for MDT proposals.

avg_cycle_time_days is a formula measure (sum(cycle_time_sum)/nullif( sum(cycle_time_count),0)) over proposals that have a request→issued cycle time, so multi-bucket roll-ups stay correct. proposal_count is every proposal in the bucket.

betaexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • mediumIncluding proposals without a cycle time

    cycle_time_count counts only proposals with a request→issued cycle time; the formula divides by it, not by proposal_count, so undated proposals don't bias the average toward zero.

  • lowAveraging avg_cycle_time_days across buckets

    It is a formula measure; do not average the per-bucket value client-side.

Questions this answers
  • “What is the average proposal turnaround by study type?”
  • “Does the escalated review path lengthen cycle time?”
7 of 7
Column
Type
Description
Tests · PII
issued_month
Date
First day of issued month. Grain + sort key.
1 test
entity
LowCardinality(String)
Issuing Smithers legal entity. Dimension + sort key.
1 test
study_type
LowCardinality(String)
Study type. Dimension + sort key.
1 test
review_path
LowCardinality(String)
standard / escalated. Dimension + sort key.
1 test
proposal_count
UInt64
Count of proposals in the bucket.
1 test
cycle_time_sum
Int64
Sum of cycle_time_days over proposals with a cycle time. Numerator of avg_cycle_time_days.
1 test
cycle_time_count
UInt64
Count of proposals with a non-null cycle time. Denominator of avg_cycle_time_days.
1 test

Mdt Pipeline

metrics.metric_mdt_pipeline
metriccertifiedbuild skippedtests 6 declareddata-eng@example.com

MDT proposal pipeline — count and summed base ROM by entity/region/study type/status over time.

The certified pipeline metric for the medical-device testing-services domain. proposal_count is the number of proposals in a bucket; total_rom is the summed base ROM (ex-VAT ex-contingency) — quoted-pipeline value, not booked revenue. Keyed on issued_month.

certifiedexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • highReading total_rom as booked revenue

    total_rom sums the base ROM of every proposal regardless of status (issued/draft/won/lost). It is quoted-pipeline value. Filter status='won' for booked value.

  • mediumAveraging avg_cycle across buckets

    Cycle time is exposed by the dedicated mdt_cycle_time metric (formula measure); do not average the pipeline mart's avg column client-side.

Questions this answers
  • “What is the MDT pipeline ROM by study type this year?”
  • “How many proposals per status by entity?”
7 of 7
Column
Type
Description
Tests · PII
issued_month
Date
First day of issued month. Grain + sort key.
1 test
entity
LowCardinality(String)
Issuing Smithers legal entity. Dimension + sort key.
1 test
region
LowCardinality(String)
Client region. Dimension + sort key.
1 test
study_type
LowCardinality(String)
Study type. Dimension + sort key.
1 test
status
LowCardinality(String)
Proposal lifecycle status. Dimension + sort key.
1 test
proposal_count
UInt64
Count of proposals in the bucket. Summed by the metric layer.
1 test
total_rom_sum
Nullable(Decimal(38, 2))
Summed base ROM. Exposed as the total_rom measure (sum). Confidential-commercial aggregate.

Mdt Proposal Economics

metrics.metric_mdt_proposal_economics
metricbetabuild skippedtests 6 declareddata-eng@example.com

MDT proposal ROM economics — summed/average ROM and contingency attach rate.

total_rom is the summed base ROM; avg_rom is a formula measure (sum(total_rom_sum)/nullif(sum(proposal_count),0)); contingency_attach_rate is a formula measure (sum(contingency_count)/nullif(sum(proposal_count),0)) — the share of proposals offering a contingency uplift. Pricing amounts are exposed here only as aggregates, never per-proposal to AI.

betaexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • highReading total_rom as booked revenue

    total_rom sums quoted base ROM across all proposals regardless of outcome; it is not realised revenue.

  • mediumRecomputing avg_rom client-side

    avg_rom is a formula measure; averaging pre-summed ROM across buckets of unequal size is an avg-of-averages and biased.

Questions this answers
  • “What is the average ROM by study type?”
  • “What share of proposals include a contingency option?”
7 of 7
Column
Type
Description
Tests · PII
issued_month
Date
First day of issued month. Grain + sort key.
1 test
entity
LowCardinality(String)
Issuing Smithers legal entity. Dimension + sort key.
1 test
study_type
LowCardinality(String)
Study type. Dimension + sort key.
1 test
currency
LowCardinality(String)
ISO currency code. Dimension + sort key.
1 test
proposal_count
UInt64
Count of proposals in the bucket.
1 test
total_rom_sum
Decimal(38, 2)
Summed base ROM. Exposed as total_rom (sum); denominator of avg_rom. Confidential-commercial aggregate.
contingency_count
UInt64
Count of proposals offering a contingency uplift. Numerator of contingency_attach_rate.
1 test

Mdt Rfp Intake

metrics.metric_mdt_rfp_intake
metricbetabuild skippedtests 7 declareddata-eng@example.com

Incoming RFP intake volume by month, channel, study type, and pipeline status.

rfp_count is the number of incoming RFPs in a bucket, keyed on received_month with entity / region / study_type / channel / intake_status dimensions. Measures the pre-proposal intake funnel — not proposals or wins (only intake_status='quoted' RFPs became proposals).

betaexpertdata-eng@example.comlast reviewed2026-07-04
Watch out for
  • highReading rfp_count as proposals or wins

    rfp_count is incoming-request volume. Only RFPs with intake_status='quoted' became proposals; use mdt_pipeline / mdt_win_rate for proposal-grain analysis.

  • mediumIgnoring status when sizing the live queue

    The live/open queue is intake_status in (received, qualifying, on_hold); quoted/declined are closed intake outcomes.

Questions this answers
  • “How many RFPs came in by channel this year?”
  • “What's the intake pipeline by status and study type?”
7 of 7
Column
Type
Description
Tests · PII
received_month
Date
First day of received month. Grain + sort key.
1 test
entity
LowCardinality(String)
Target Smithers legal entity. Dimension + sort key.
1 test
region
LowCardinality(String)
Client region. Dimension + sort key.
1 test
study_type
LowCardinality(String)
Study type requested. Dimension + sort key.
1 test
channel
LowCardinality(String)
Intake channel. Dimension + sort key.
1 test
intake_status
LowCardinality(String)
Intake-pipeline stage. Dimension + sort key.
1 test
rfp_count
UInt64
Count of incoming RFPs in the bucket.
1 test

Mdt Win Rate

metrics.metric_mdt_win_rate
metricbetabuild skippedtests 7 declareddata-eng@example.com

Share of decided MDT proposals that were won, by month/entity/study type/review path.

won_count counts won proposals; decided_count counts won+lost; win_rate is a formula measure (sum(won_count)/nullif(sum(decided_count),0)) so it stays window-correct. Most historical Smithers proposals are 'issued' (outcome unknown), so decided_count is small by design — win_rate reflects only proposals with a recorded outcome.

betaexpertdata-eng@example.comlast reviewed2026-07-03
Watch out for
  • highTreating issued proposals as losses

    Only won/lost proposals are decided. Undecided ('issued') proposals are excluded from decided_count — do not treat them as losses.

  • mediumDividing summed columns client-side

    win_rate is a formula measure; dividing pre-aggregated won/decided columns across a window yields a biased number.

Questions this answers
  • “What is the MDT win rate by study type?”
  • “Win rate on the escalated vs standard review path?”
7 of 7
Column
Type
Description
Tests · PII
issued_month
Date
First day of issued month. Grain + sort key.
1 test
entity
LowCardinality(String)
Issuing Smithers legal entity. Dimension + sort key.
1 test
study_type
LowCardinality(String)
Study type. Dimension + sort key.
1 test
review_path
LowCardinality(String)
standard / escalated. Dimension + sort key.
1 test
won_count
Nullable(UInt64)
Count of won proposals in the bucket. Win-rate numerator.
1 test
decided_count
Nullable(UInt64)
Count of decided (won+lost) proposals. Win-rate denominator.
1 test
proposal_count
UInt64
Count of all proposals in the bucket.
1 test

Pick Accuracy

metrics.metric_pick_accuracy
metricbetabuild 1d agotests 6/6 passinglogistics-analytics@example.com

Share of order lines picked accurately, by site (region-level rollup), segment, and temp class.

Pick accuracy over shipped order lines, bucketed by `ship_month` (`toStartOfMonth(ship_date)`), `site`, `client_segment`, and `temp_class`. `accurate_lines` counts lines picked accurately; `total_lines` counts all lines. `pick_accuracy` is exposed as a FORMULA measure (sum(accurate_lines) / nullif(sum(total_lines), 0)) so it remains correct across any window — never divide the two count columns client-side. The `site` dimension is REGION-LEVEL: it is `site_region` rolled into the `site` label, because `mart_fulfillment_daily`'s grain does not carry `site_id`. A true `site_id`-level pick-accuracy breakdown is not available in P0 without widening the mart's grain — do not present these region-level numbers as site-level.

betaexpertlogistics-analytics@example.comlast reviewed2026-07-01
Watch out for
  • highDividing the two count columns client-side

    `accurate_lines` and `total_lines` are counts. Request the `pick_accuracy` formula measure — the metric layer divides with `nullif` window-correctly. Dividing the summed columns yourself across multiple buckets is an average-of-averages, biased.

  • mediumReading total_lines as an order count

    `total_lines` counts order LINES, not orders — an order has many lines. Do not read it as `order_count` (that lives on the `fulfillment` metric); the two are different grains of counting.

  • mediumReading the `site` dimension as site_id-level

    The `site` dimension is REGION-LEVEL in P0 (it is `site_region`); the source rollup does not carry `site_id`. Do not attribute a region-level accuracy number to an individual warehouse.

Questions this answers
  • “How does pick accuracy trend by temp class?”
  • “Which region has the best pick accuracy this quarter?”
  • “Pick accuracy for life_sciences clients over the last 6 months.”
Related metrics
  • fulfillment

    Fed by the same `mart_fulfillment_daily` rollup — pairs picking quality (line accuracy) with delivery performance (OTIF / on-time / in-full) for the same period.

6 of 6
Column
Type
Description
Tests · PII
ship_month
Date
First day of the ship month (toStartOfMonth of ship_date). Grain + sort key.
1 test
site
LowCardinality(String)
Region-level site rollup (= `site_region`; the source rollup does not carry site_id) — EU / UK / NA / APAC; `unknown` when unmapped. Dimension + sort key.
1 test
client_segment
LowCardinality(String)
Owning-client segment — automotive / chemicals / fmcg / fashion / high_tech / life_sciences; `unknown` when unmapped. Dimension + sort key.
1 test
temp_class
LowCardinality(String)
Temperature class — ambient / chilled / frozen; `unknown` when unmapped. Dimension + sort key.
1 test
accurate_lines
UInt64
Sum of accurately-picked lines in the bucket. Numerator of the `pick_accuracy` formula measure.
1 test
total_lines
UInt64
Sum of total order lines in the bucket. Denominator of the `pick_accuracy` formula measure (lines, not orders).
1 test

Proposal Economics

metrics.metric_proposal_economics
metricbetabuild 1d agotests 7/7 passingrfx-analytics@example.com

Average margin, cycle time, and won value by decision month, segment, and region.

Monthly proposal economics rolled up by deal segment and region over **decided** proposals only (won + lost). `avg_margin_pct` is the average of per-proposal margin_pct; `avg_cycle_time_days` is the average decision cycle time (decision_date − submitted_date); `won_value` is realised won deal value — sumIf(total_price, is_won), where is_won = (outcome = 'won'). Pending and withdrawn proposals are excluded because their decision_date is NULL and their economics are incomplete — sweeping them in would bias margin and cycle-time averages. The gateway re-aggregates with avg() / sum() over the caller's chosen dimensions.

betaexpertrfx-analytics@example.comlast reviewed2026-06-28
Watch out for
  • highTreating these averages as covering all proposals

    This metric includes decided proposals only (outcome in ('won','lost')). Pending / withdrawn proposals have a NULL decision_date and are excluded by construction — the averages describe the decided book, not the full pipeline. For still-open volume use the `rfx_pipeline` metric.

  • highReading `won_value` as total submitted value

    `won_value` is realised won deal value only — sumIf(total_price, is_won). Lost-proposal prices are excluded. It is NOT the total priced value across all decided proposals; pair with `proposal_win_rate` for the win conversion view.

  • mediumRecomputing the averages from summed columns client-side

    `avg_margin_pct` and `avg_cycle_time_days` are avg() measures. The gateway re-runs avg() over the chosen window; dividing two already-aggregated outputs across multiple months yields a sum-of-averages bias.

Questions this answers
  • “What is the average proposal margin by segment this year?”
  • “How much won deal value did we close by region last quarter?”
  • “What is the average decision cycle time by segment?”
Related metrics
  • proposal_win_rate

    Win conversion (won_count / decided_count) over the same decided book — pair to read margin and cycle time alongside how often proposals are won.

  • rfx_pipeline

    Open-opportunity pipeline (count, est_value, probability) — the upstream view before proposals are decided here.

6 of 6
Column
Type
Description
Tests · PII
decision_month
Date
Month bucket — `toStartOfMonth(decision_date)`. Grain + sort key.
1 test
segment
LowCardinality(String)
Account segment — `enterprise` / `mid` / `smb`; `unknown` when unmapped. Dimension + sort key.
1 test
region
LowCardinality(String)
Opportunity region — `NA` / `EMEA` / `APAC` / `LATAM`; `unknown` when unmapped. Dimension + sort key.
1 test
avg_margin_pct
Decimal(6, 2)
Average of per-proposal `margin_pct` across decided proposals in the bucket. Decimal(6,2).
1 test
avg_cycle_time_days
Decimal(10, 2)
Average decision cycle time (decision_date − submitted_date) in days across decided proposals. Decimal(10,2).
1 test
won_value
Decimal(14, 2)
Realised won deal value — `sumIf(total_price, is_won)` over the bucket, where is_won = (outcome = 'won'). Lost-proposal prices are excluded. Decimal(14,2).
2 tests

Proposal Win Rate

metrics.metric_proposal_win_rate
metricbetabuild 1d agotests 6/6 passingrfx-analytics@example.com

Share of decided proposals that were won, by decision month and deal cut.

Win rate over decided proposals (won + lost), bucketed by the month the decision landed (`toStartOfMonth(decision_date)`) and the deal's segment, region, and rfx_type. `decided_count` counts every proposal that reached a won/lost decision; `won_count` counts the wins. `win_rate` is exposed as a formula measure (sum(won_count) / nullif(sum(decided_count), 0)) so it remains correct across any window. Pending and withdrawn proposals are excluded entirely — they are NOT counted as losses, and they do not appear in any month because their decision_date is NULL.

betaexpertrfx-analytics@example.comlast reviewed2026-06-28
Watch out for
  • highTreating pending or withdrawn proposals as losses

    This metric considers only decided proposals (outcome in ('won','lost')). Pending and withdrawn proposals are excluded from both `decided_count` and `won_count` — they are not silently counted as losses. A denominator that includes pending deals understates the win rate.

  • mediumRecomputing win_rate by dividing summed columns client-side

    `win_rate` is a formula measure (sum(won_count) / nullif(sum( decided_count), 0)) — correct under any window. Dividing two already-aggregated outputs across a multi-month window yields a different (biased) number than the formula.

  • mediumBucketing by submitted month instead of decision month

    The grain is the decision month (`toStartOfMonth(decision_date)`), so a proposal lands in the month it was won/lost, not when it was submitted. For cycle-time-to-decision use the `proposal_economics` metric instead.

Questions this answers
  • “What was the proposal win rate over the last 6 months?”
  • “Which segments have the highest win rate this year?”
  • “How does win rate compare across RFP, RFQ and RFI by region?”
Related metrics
  • proposal_economics

    Carries margin and cycle-time-to-decision for the same decided proposals — pair with win_rate to see whether wins are profitable.

  • rfx_pipeline

    Upstream opportunity pipeline (count + est_value) that feeds the proposals this win rate is computed over.

6 of 6
Column
Type
Description
Tests · PII
decision_month
Date
Month bucket — `toStartOfMonth(decision_date)`. Grain + sort key.
1 test
segment
LowCardinality(String)
Deal segment — enterprise / mid / smb; `unknown` when unmapped. Dimension + sort key.
1 test
region
LowCardinality(String)
Deal region — NA / EMEA / APAC / LATAM; `unknown` when unmapped. Dimension + sort key.
1 test
rfx_type
LowCardinality(String)
RFx type — RFP / RFQ / RFI; `unknown` when unmapped. Dimension + sort key.
1 test
decided_count
UInt64
Count of decided proposals (outcome in ('won','lost')) in the bucket. The win-rate denominator.
1 test
won_count
UInt64
Count of won proposals in the bucket (is_won or outcome = 'won'). The win-rate numerator.
1 test

Returns By Month

metrics.metric_returns_by_month
metriccertifiedbuild 1d agotests 7/7 passinganalytics@example.com

Monthly returns and refunded value — the certified figure.

Approved monthly returns, built on `mart_returns_daily`. `returns_count` is the number of return requests; `refunded_amount` is realised refunds only (returns that reached `refunded`). `avg_refund_per_return` is a formula measure (sum(refunded_amount) / nullif(sum(returns_count), 0)) so it stays correct across any window. There is NO sales denominator here — to compute a return RATE, pair `returns_count` with `orders_count` from `revenue_by_month` over the same window.

certifiedexpertanalytics@example.comlast reviewed2026-05-30
Watch out for
  • highTreating `returns_count` as refunds

    `returns_count` counts every request (requested/approved/received/ refunded/rejected). Only `refunded_amount` is money actually returned. Use refunded_amount for financial leakage, returns_count for operational volume.

  • highComputing a return rate from this metric alone

    This metric has no order/sales denominator. A return RATE = returns_count / orders_count needs `orders_count` from `revenue_by_month` over the same window. Dividing by any measure here is wrong.

  • mediumRecomputing `avg_refund_per_return` client-side

    `avg_refund_per_return` is a formula measure (sum/sum). Dividing two already-aggregated outputs across a multi-month window yields a different (biased) number.

Questions this answers
  • “How many returns and how much refunded per month over the last 6 months?”
  • “Which product categories drove the most refunded value this year?”
  • “What are the top return reasons by refunded value?”
Related metrics
  • revenue_by_month

    Provides `orders_count` — the denominator for a true return rate, and the revenue context for refund-leakage analysis.

  • product_reviews

    Returns for `defective` / `damaged_in_transit` reasons corroborate low review scores; cross-check categories that spike in both.

6 of 6
Column
Type
Description
Tests · PII
return_month
Date
Month bucket — `toStartOfMonth(return_day)`. Sort key.
1 test
product_category
String
Product category of the returned item; `unknown` when unmapped. Dimension + sort key.
1 test
return_reason
String
Reason bucket for the return. Dimension + sort key.
1 test
returns_count
UInt64
Number of return requests (all statuses) in the month/category/reason bucket.
1 test
units_returned
UInt64
Total units returned in the bucket.
1 test
refunded_amount
Decimal(14, 2)
Sum of refund_amount for `refunded` returns only. Decimal(14,2).
2 tests

Returns Rate

metrics.metric_returns_rate
metricbetabuild 1d agotests 6/6 passinglogistics-analytics@example.com

Return rate (returns per shipped order), disposition mix, and processing cycle time by segment and region.

Returns rolled up from the per-return `mart_returns` to (return_month × client_segment × site_region × disposition), where `return_month` is `toStartOfMonth(return_date)`. `return_count` counts returns; `return_value_sum` is the summed value of returned goods (Nullable(Decimal(38,2)) — sum() of Decimal(14,2) promotes to Decimal(38,2)); `avg_return_cycle_days` is the average processing cycle time (Nullable(Float64) — avg() semantics). `shipped_order_count` is the shipped-order denominator, materialized from `mart_fulfillment_daily` at the COARSER (return_month × client_segment × site_region) grain (NO disposition) and repeated across the disposition rows for that month/segment/region. `return_rate` is a FORMULA measure (sum(return_count) / nullif(sum(shipped_order_count), 0)). Both feeds coalesce `client_segment` / `site_region` identically to `unknown` so no bucket drops. The rate is APPROXIMATE — returns are matched to their shipping calendar month, not their exact shipping cohort.

betaexpertlogistics-analytics@example.comlast reviewed2026-07-01
Watch out for
  • highSlicing return_rate by disposition

    `return_rate` is APPROXIMATE and the shipped denominator carries NO disposition — `shipped_order_count` is repeated across disposition buckets. Do NOT slice `return_rate` by `disposition` (it would double-count the denominator). Returns are matched to their shipping CALENDAR MONTH, not their exact shipping cohort.

  • highReading return_count as the return rate

    `return_count` is a raw count of returns, not a rate. Request the `return_rate` formula measure — it divides by `shipped_order_count` with `nullif` window-correctly. Use `return_count` for volume / disposition mix, `return_rate` for the rate.

  • mediumSumming avg_return_cycle_days across buckets

    `avg_return_cycle_days` is an avg() measure — the metric layer re-runs avg() over the chosen window. Do not roll it up client-side (summing or averaging pre-averaged values is biased).

Questions this answers
  • “What is the return rate by segment this year?”
  • “What is the disposition mix of returns by region?”
  • “What is the average return processing cycle time by segment?”
Related metrics
  • fulfillment

    Supplies the shipped-order count (`order_count`) that is this metric's return-rate denominator — pair to read returns against upstream fulfillment volume for the same segment / region.

8 of 8
Column
Type
Description
Tests · PII
return_month
Date
First day of the return month (toStartOfMonth of return_date). Grain + sort key.
1 test
client_segment
LowCardinality(String)
Owning-client segment — automotive / chemicals / fmcg / fashion / high_tech / life_sciences; `unknown` when unmapped. Dimension + sort key. Coalesced identically to the shipped feed.
1 test
site_region
LowCardinality(String)
Handling-site region — EU / UK / NA / APAC; `unknown` when unmapped. Dimension + sort key. Coalesced identically to the shipped feed.
1 test
disposition
LowCardinality(String)
Return disposition — restock / repair / recycle / scrap; `unknown` when unmapped. Dimension + sort key. NOT carried by the shipped denominator (do not slice return_rate by it).
1 test
return_count
UInt64
Count of returns in the bucket. Numerator of the `return_rate` formula measure.
1 test
shipped_order_count
UInt64
Shipped-order denominator from `mart_fulfillment_daily` at the coarser (return_month × client_segment × site_region) grain — NO disposition, repeated across the disposition rows. Denominator of the `return_rate` formula measure. 0 when no matching shipped bucket exists.
1 test
avg_return_cycle_days
Nullable(Float64)
Average return processing cycle time (days) in the bucket. Exposed as the `avg_return_cycle_days` measure (avg). Nullable(Float64) per §0.3 (avg() returns Nullable(Float64)).
return_value_sum
Nullable(Decimal(38, 2))
Sum of returned-goods value in the bucket. Exposed as the `return_value_sum` measure (sum). Nullable(Decimal(38,2)) per §0.3 (sum() of Decimal(14,2) promotes to Decimal(38,2)).

Revenue By Month

metrics.metric_revenue_by_month
metriccertifiedbuild 1d agotests 5/5 passinganalytics@example.com

Monthly revenue, the certified figure.

Approved monthly revenue, built on top of `mart_revenue_daily` so daily and monthly numbers reconcile by construction. Lives in the `metrics` ClickHouse database — the curated surface the AI assistant routes through. AOV is exposed as a formula measure to avoid sum-of-averages bias across multi-month windows.

certifiedexpertanalytics@example.comlast reviewed2026-05-19
Watch out for
  • highTreating `unique_customer_days` as monthly active customers

    `unique_customer_days` SUMs the daily distinct-customer counts — a customer who orders on three days in a month contributes 3. It is an active-customer-day measure, NOT a deduped MAU. For a true distinct count use the `customer_health` metric.

  • mediumRecomputing AOV by dividing summed columns client-side

    `avg_order_value` is a formula measure (sum(revenue) / nullif(sum(orders_count), 0)) — correct under any window. Dividing two already-aggregated outputs yields a different number across multi-month windows.

Questions this answers
  • “What was monthly revenue over the last 6 months?”
  • “What is the average order value trend by month this year?”
5 of 5
Column
Type
Description
Tests · PII
order_month
Date
Month bucket — `toStartOfMonth(order_day)`. Sort key.
2 tests
orders_count
UInt64
Total revenue-eligible orders in the month (sum of daily counts).
1 test
revenue
Decimal(14, 2)
Total revenue in the month (sum of daily revenue). Decimal(14,2).
2 tests
unique_customer_days
UInt64
Sum of daily `unique_customers` across the month — NOT a distinct customer count over the month. A customer who orders on three separate days contributes 3 here. Use this as an "active customer-day" measure, not as a deduped monthly active customer count.
avg_order_value
Decimal(14, 2)
Derived — `revenue / orders_count`. Decimal(14,2). Null when `orders_count` is 0.

Rfx Pipeline

metrics.metric_rfx_pipeline
metriccertifiedbuild 1d agotests 9/9 passingdata-eng@example.com

Open RFX pipeline — count, estimated value, and win probability by stage / segment / region over time.

The certified open-pipeline metric for the procurement / RFX-response domain. One row per (issued_month × segment × region × stage) carrying `opp_count` (opportunities in the bucket), `est_value_sum` (summed ESTIMATED deal value — pipeline coverage, NOT booked revenue), and `avg_probability` (per-bucket mean win probability, 0..100). `issued_month` is the month the RFX was issued (toStartOfMonth of issued_date), so this is a trend surface — pair the `stage` dimension with it to watch the pipeline move from `qualifying` through `won` / `lost` / `no_bid`. The metric layer exposes `est_value` as a SUM and `avg_probability` as an AVG so multi-bucket roll-ups recompute correctly rather than summing pre-averaged values. Nullable segment / region / stage are coalesced to `unknown` upstream so they stay visible rather than dropped.

certifiedexpertdata-eng@example.comlast reviewed2026-06-28
Watch out for
  • highTreating est_value as won / booked revenue

    `est_value` sums the ESTIMATED deal size across every opportunity in the bucket regardless of stage — it includes `qualifying`, `in_progress`, `lost`, and `no_bid`. It is a pipeline-coverage figure, not realised revenue. Filter `stage = 'won'` (or use the `proposal_economics` metric) before reading it as closed value.

  • mediumRecomputing avg_probability by averaging the column client-side

    `avg_probability` is a per-bucket average of the UInt8 0..100 probability. The metric layer exposes it as an AVG aggregate so the gateway recomputes it correctly over the requested dimensions. Averaging the already-averaged column across buckets of unequal size is an avg-of-averages — biased. Always request it as the `avg_probability` measure, never derive it client-side.

  • mediumReading a single month as the full open pipeline

    The grain is keyed on `issued_month` (when the RFX was issued), not a snapshot date. A deal issued in March that is still `in_progress` lives in March's bucket — sum across the relevant `issued_month` range to see total open pipeline, don't read one month in isolation.

Questions this answers
  • “What is the open RFX pipeline value by stage this quarter?”
  • “How many RFX opportunities are in each segment, by region?”
  • “Average win probability of deals by stage over the last 6 months.”
Related metrics
  • proposal_win_rate

    `rfx_pipeline` sizes the open funnel; `proposal_win_rate` measures how much of it converts. Pair them to read coverage against conversion for the same segment / region.

  • proposal_economics

    For deals that closed, `proposal_economics` carries realised margin, cycle time, and won value — the booked counterpart to this metric's estimated pipeline value.

7 of 7
Column
Type
Description
Tests · PII
issued_month
Date
First day of the month the RFX was issued (toStartOfMonth of issued_date). Grain + sort / partition key.
1 test
segment
String
Account segment behind the opportunity — `enterprise`, `mid`, `smb`, or `unknown`. Dimension + sort key.
1 test
region
String
Opportunity region — `NA`, `EMEA`, `APAC`, `LATAM`, or `unknown`. Dimension + sort key.
1 test
stage
String
Pipeline stage — `qualifying`, `in_progress`, `submitted`, `won`, `lost`, `no_bid`, or `unknown`. Dimension + sort key.
1 test
opp_count
UInt64
Count of opportunities in the bucket. Summed by the metric layer over the requested dimensions.
2 tests
est_value_sum
Nullable(Decimal(38, 2))
Sum of estimated deal value (est_value) across opportunities in the bucket. Exposed as the `est_value` measure (sum). Pipeline coverage, NOT booked revenue.
2 tests
avg_probability
Nullable(Float64)
Per-bucket mean win probability (0..100), rounded to 2 decimals. Exposed as the `avg_probability` measure (avg) so multi-bucket roll-ups recompute correctly.
1 test
intermediate

Joins and shared logic

17 entries

Reusable building blocks — the joins, deduplications, and per-customer rollups that more than one mart depends on. Not meant for direct querying.

Ap Aging

intermediate.int_ap__aging
intermediatetests none declareddata-eng@example.com
accessOperator only

Open AP per bill, aged into buckets.

One row per open vendor bill with its remaining functional-USD balance, days overdue from due_date, and aging bucket (current / 1_30 / 31_60 / 61_90 / 90_plus) as of the snapshot day.

Ar Aging

intermediate.int_ar__aging
intermediatetests none declareddata-eng@example.com
accessOperator only

Open AR per invoice, aged into buckets.

One row per open customer invoice with its remaining functional-USD balance, days overdue from due_date, and aging bucket (current / 1_30 / 31_60 / 61_90 / 90_plus) as of the snapshot day.

Close Status

intermediate.int_close__status
intermediatetests none declareddata-eng@example.com
accessOperator only

Where each period stands in the close.

Per-period rollup of the signals a controller checks before locking a period: posted vs draft entries, whether the trial balance ties, and bank reconciliations opened vs balanced.

Finance Periods

intermediate.int_finance__periods
intermediatetests none declareddata-eng@example.com
accessOperator only

The fiscal periods, typed.

One row per fiscal period with its code, year/month, date range, month bucket (`period_month_start`), and close status. The period dimension the finance marts roll up on.

Gl Trial Balance

intermediate.int_gl__trial_balance
intermediatebuild 1d agotests 2 declareddata-eng@example.com
accessOperator only

Posted-only debit/credit/net per account, period, cost center.

Per (period, gl_account, cost_center) sum of debits and credits over posted lines, plus the net (debit minus credit). The standing balance the trial balance and GL marts are built from.

7 of 7
Column
Description
Tests · PII
period_id
FK to int_finance__periods.period_id (from the entry header).
gl_account_id
FK to stg_postgres__gl_accounts.gl_account_id.
cost_center_id
Cost center; 0 when the line carried none (kept non-null for the sort key).
debit_amount
Sum of posted debits in functional USD. Decimal(18,2).
credit_amount
Sum of posted credits in functional USD. Decimal(18,2).
net_amount
Derived — sum(debit) - sum(credit). The balance. Decimal(18,2).
line_count
Number of posted lines in the bucket. UInt64.

Inventory With Category

intermediate.int_inventory__with_category
intermediatetests none declareddata-eng@example.com
accessOperator only

Inventory snapshots + product category.

Per-snapshot product enrichment. Adds `category` (coalesced to `'unknown'`) and `is_stockout` (on_hand_qty = 0). Otherwise a pass-through of the staging snapshot row.

Marketing Engagement

intermediate.int_marketing_engagement
intermediatetests none declaredmarketing-eng@example.com
accessOperator only

Marketing sends decorated with campaign + funnel flags.

Per-send join — carries campaign channel + audience_segment + optional promotion_id, plus derived booleans for each funnel stage (`is_delivered`, `is_opened`, `is_clicked`, `is_unsubscribed`, `is_bounced`). On the positive path the flags cascade (clicked implies opened implies delivered); `is_bounced` is mutually exclusive with `is_delivered`.

Orders Enriched

intermediate.int_orders__enriched
intermediatetests none declareddata-eng@example.com
accessOperator only

Orders, decorated with the customer behind them.

Ephemeral join — attaches customer country, segment, and signup date to each order, plus a derived `is_revenue_order` flag (`status not in (cancelled, refunded)`). Inlined into `mart_customers`, `mart_orders_daily`, and `mart_revenue_daily` so revenue-eligibility stays consistent across them.

Payments Order Join

intermediate.int_payments__order_join
intermediatetests none declareddata-eng@example.com
accessOperator only

Payments, decorated with order + method context.

Ephemeral join — attaches order header (customer_id, status, order_at) and payment-method metadata (method_type, card_brand) to each payment row, plus lifecycle booleans (`is_final_capture`, `is_refund`, `is_failed_auth`, `is_void`, `is_failure`). Revenue eligibility = `is_final_capture` (capture row with status succeeded); naively summing `amount` double-counts auth+capture.

Promotions Order Join

intermediate.int_promotions__order_join
intermediatetests none declareddata-eng@example.com
accessOperator only

Promo applications with order + segment context.

Per-(order × promotion) join. Computes `net_order_amount = max(gross - discount, 0)` (floors at 0 to handle the rare legacy data where discount exceeds the order subtotal). Carries customer segment and country for downstream slicing.

Rfx Opportunity Enriched

intermediate.int_rfx__opportunity_enriched
intermediatetests 2/2 passing1 PII columndata-eng@example.com
accessOperator only

Opportunities, decorated with account + owning SME.

Ephemeral join — attaches account attributes (account_name, segment, tier, annual_revenue_band) and the owning SME's name + department to each RFX opportunity, keeping the derived `issued_month`. Account and SME are LEFT-joined, so an opportunity whose FK is missing surfaces NULL (coalesced to `unassigned` / `unknown` for the SME columns) rather than dropping the row — the relationships tests in staging are what flag the bad FK. Inlined into `mart_rfx_pipeline`.

Rfx Proposal Economics

intermediate.int_rfx__proposal_economics
intermediatetests 4/4 passingdata-eng@example.com
accessOperator only

Proposals, decorated with the deal's segment / region / type + economics.

Ephemeral join — chains proposals → opportunities → accounts so each proposal carries the deal's `segment` (off the account), `region` and `rfx_type` (off the opportunity), plus `account_id`. Exposes `total_price`, `total_cost`, `margin_pct` ((price−cost)/price·100), `cycle_time_days` (decision_date − submitted_date, Nullable while pending), `outcome`, and the derived `is_won = (outcome = 'won')`. Opportunity + account are LEFT-joined and the borrowed dims coalesce to `'unknown'`, so a proposal with a missing FK still lands (staging's relationships test flags the bad FK). Inlined into `mart_proposal_outcomes`.

Shipments Sla

intermediate.int_shipments__sla
intermediatetests none declareddata-eng@example.com
accessOperator only

Shipments with SLA timings + ship-to country.

Per-shipment SLA join. Computes `ship_lag_hours` (order → label/pickup), `transit_hours` (pickup → delivery), and `on_time` (delivered_at ≤ estimated_delivery_at). All three are Nullable until the relevant lifecycle event lands; in-flight and un-shipped rows carry NULL where the math doesn't apply.

Subscriptions Monthly Explode

intermediate.int_subscriptions__monthly_explode
intermediatetests none declareddata-eng@example.com
accessOperator only

One row per subscription × active month.

Fan-out producing (subscription × period_month) rows from started_month through exit_month (cancelled_at or today, whichever is earlier). `period_status` is `active` for every month before cancellation; the cancellation month + onward carry the terminal status (`cancelled` / `expired`). This keeps MRR (`sumIf(monthly_amount, period_status='active')`) correct — a sub cancelled mid-month does NOT contribute MRR that month.

Whse Contract Sla

intermediate.int_whse__contract_sla
intermediatetests 2/2 passingdata-eng@example.com
accessOperator only

Contracts, with SLA targets flattened + client/site attributes.

Ephemeral join — flattens otif_target_pct, pick_accuracy_target_pct, dock_to_stock_target_hrs, and billing_model onto one row per contract, decorated with client segment/tier/name, site region/type/certs, and capacity. Aliases raw start_date → term_start, end_date → term_end (INC-06); site_region coalesces raw sites.region (INC-08). Derives is_active (term_start ≤ logistics_as_of AND (term_end IS NULL OR term_end ≥ logistics_as_of) — fixed anchor, never the wall clock). Inlined into mart_client_scorecard + mart_site_performance.

Whse Inventory Valued

intermediate.int_whse__inventory_valued
intermediatetests 2/2 passingdata-eng@example.com
accessOperator only

Inventory lots, decorated with product class + velocity signals.

Ephemeral join — attaches product temp/hazard class + value/dims + the owning client_id, the storing site's region/type, and the owning client's segment to each inventory lot, plus an outbound-demand rollup (shipped units per sku × site over the trailing 90 days ending at logistics_as_of) so velocity can be derived. Derives days_of_cover (qty_on_hand / avg daily units out), turnover_ratio (units_out_window / avg_qty_on_hand), near_expiry_flag (lot_expiry within 30 days of the fixed logistics_as_of anchor — single-sourced, never the wall clock), and inv_month (toStartOfMonth(received_date), INC-12). Inlined into mart_inventory_health.

Whse Order Enriched

intermediate.int_whse__order_enriched
intermediatetests 2/2 passingdata-eng@example.com
accessOperator only

Orders, decorated with client / site / dest region + a pick-accuracy rollup.

Ephemeral join — attaches client segment/tier + home region, the fulfilling site's region/type, the coarse ship-to region (never consumer PII), and a line-level rollup (total_lines, accurate_lines, units, avg_pick_time_sec) to each outbound order. Derives cycle_time_hrs (order→ship), line_accuracy_pct, ship_month, and is_on_time (ship_date ≤ promised_date). order_value aliases raw order_value_eur (INC-11); site_region coalesces raw sites.region (INC-08). Dims LEFT-joined and coalesced to 'unknown' so a bad FK surfaces NULL (staging relationships test flags it) rather than crashing. Inlined into mart_fulfillment_daily + mart_order_outcomes.

staging

Cleaned, renamed, typed

95 entries

Each source table gets one staging model that picks the columns we use, renames awkward fields, casts types, and removes deleted rows. Staging is the first place names start to make sense.

Gcs Mdt Contacts

staging.stg_gcs__mdt_contacts
stagingbuild skippedtests 4 declared3 PII columnsdata-eng@example.com
accessOperator only

Client contacts, typed and FK-validated.

Cleaned mirror of raw_gcs.mdt_contacts — buyer-side contacts on each opportunity.

Gcs Mdt Devices

staging.stg_gcs__mdt_devices
stagingbuild skippedtests 7 declareddata-eng@example.com
accessOperator only

Devices under test, typed.

One row per device under test; nickname is the join key across tests + pricing.

Gcs Mdt Historical Matches

staging.stg_gcs__mdt_historical_matches
stagingbuild skippedtests 4 declareddata-eng@example.com
accessOperator only

Historical similarity edges, typed.

One row per (opportunity, matched past job) similarity edge.

4 tests declaredmodels/staging/testing_services/stg_gcs__mdt_historical_matches.sql
Open in lineage graph

Gcs Mdt Opportunities

staging.stg_gcs__mdt_opportunities
stagingbuild skippedtests 12 declared3 PII columnsdata-eng@example.com
accessOperator only

RFQ opportunities, typed.

Cleaned mirror of raw_gcs.mdt_opportunities — one row per Smithers job reference with client, region, entity, study type, and the RFQ date chain.

Gcs Mdt Pricing Line Items

staging.stg_gcs__mdt_pricing_line_items
stagingbuild skippedtests 9 declareddata-eng@example.com
accessOperator only

Pricing line items, typed.

One row per cost-generating activity; amounts sum to the proposal's total_rom.

9 tests declaredmodels/staging/testing_services/stg_gcs__mdt_pricing_line_items.sql
Open in lineage graph

Gcs Mdt Proposals

staging.stg_gcs__mdt_proposals
stagingbuild skippedtests 11 declared3 PII columnsdata-eng@example.com
accessOperator only

Proposals, typed.

One row per proposal — status, entity, ROM, review path, cycle time.

Gcs Mdt Rate Card

staging.stg_gcs__mdt_rate_card
stagingbuild skippedtests 11 declareddata-eng@example.com
accessOperator only

Per-test rate card, typed.

One row per (related_test, category); related_test is a canonical test family or a raw-name alias, unit_rate_minor is the GBP-pence rate.

Gcs Mdt Rfps

staging.stg_gcs__mdt_rfps
stagingbuild skippedtests 9 declared1 PII columndata-eng@example.com
accessOperator only

Incoming RFPs, typed.

One row per incoming RFP/RFQ in the intake queue, with status + requested scope.

Gcs Mdt Sme Directory

staging.stg_gcs__mdt_sme_directory
stagingbuild skippedtests 2 declared3 PII columnsdata-eng@example.com
accessOperator only

Smithers SMEs, typed.

One row per named Smithers SME — role, site, entity, peer-review/escalation flags.

Gcs Mdt Standards

staging.stg_gcs__mdt_standards
stagingbuild skippedtests 3 declareddata-eng@example.com
accessOperator only

Standards catalog, typed.

One row per referenced standard, linked to its full-text PDF blob.

Gcs Mdt Test Methods

staging.stg_gcs__mdt_test_methods
stagingbuild skippedtests 8 declareddata-eng@example.com
accessOperator only

Tests per device, typed.

One row per (device, test) — the technical scope behind a proposal.

Gcs Product Reviews

staging.stg_gcs__product_reviews
stagingbuild 1d agotests 19/19 passing2 PII columnsdata-eng@example.com
accessOperator only

Reviews, typed and FK-validated.

Cleaned mirror of `raw_gcs.product_reviews`. Coerces the CSV's `Nullable(String)` columns into proper types, derives `review_day` from the submission timestamp, and enforces FK relationships against `stg_postgres__customers` and `stg_postgres__products` so unknown IDs fail tests instead of landing silently.

Gcs Rfx Accounts

staging.stg_gcs__rfx_accounts
stagingbuild 1d agotests 18/18 passingdata-eng@example.com
accessOperator only

Buying accounts, typed.

Cleaned mirror of `raw_gcs.rfx_accounts`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and derives `created_day` from the creation timestamp. No personal data — an account is a company, not a natural person.

Gcs Rfx Approval Rules

staging.stg_gcs__rfx_approval_rules
stagingbuild 1d agotests 16/16 passingdata-eng@example.com
accessOperator only

Approval-workflow rules, typed.

Cleaned mirror of `raw_gcs.rfx_approval_rules`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. Reference data describing the approval workflow that gates proposals on discount, value, margin, and legal terms — no personal data.

Gcs Rfx Contacts

staging.stg_gcs__rfx_contacts
stagingbuild 1d agotests 7/7 passing3 PII columnsdata-eng@example.com
accessOperator only

Buyer-side contacts, typed and FK-validated.

Cleaned mirror of `raw_gcs.rfx_contacts`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces the FK to `stg_gcs__rfx_accounts` so an unknown account fails tests instead of landing silently. The name/email/phone columns are tagged PII so masking + erasure fire end-to-end.

Gcs Rfx Opportunities

staging.stg_gcs__rfx_opportunities
stagingbuild 1d agotests 27/27 passingdata-eng@example.com
accessOperator only

RFX opportunities, typed and FK-validated.

Cleaned mirror of `raw_gcs.rfx_opportunities`. Coerces the CSV's `Nullable(String)` columns into typed equivalents, derives `issued_month` via `toStartOfMonth(issued_date)`, and enforces FKs to `stg_gcs__rfx_accounts` and `stg_gcs__rfx_sme_directory`. The `source_uri` is the reconciliation key into the `rfx-documents` corpus.

Gcs Rfx Permissions

staging.stg_gcs__rfx_permissions
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

The procurement RBAC matrix, typed.

Cleaned mirror of `raw_gcs.rfx_permissions`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. Reference data describing the intended access policy for procurement personas — no personal data.

Gcs Rfx Price Book

staging.stg_gcs__rfx_price_book
stagingbuild 1d agotests 15/15 passingdata-eng@example.com
accessOperator only

Region/segment pricing guardrails, typed and FK-validated.

Cleaned mirror of `raw_gcs.rfx_price_book`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces the FK to `stg_gcs__rfx_products_services` so an unknown SKU fails tests. The grain is one row per (sku × region × segment).

Gcs Rfx Products Services

staging.stg_gcs__rfx_products_services
stagingbuild 1d agotests 15/15 passingdata-eng@example.com
accessOperator only

The quotable catalog, typed.

Cleaned mirror of `raw_gcs.rfx_products_services`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. The source of truth for SKU names referenced by the price book.

Gcs Rfx Proposals

staging.stg_gcs__rfx_proposals
stagingbuild 1d agotests 14/14 passingdata-eng@example.com
accessOperator only

Submitted proposals, typed and FK-validated.

Cleaned mirror of `raw_gcs.rfx_proposals`. Coerces the CSV's `Nullable(String)` columns into typed equivalents (decision_date, eval_score, source_uri, and cycle_time_days stay Nullable to model pending/withdrawn proposals) and enforces FKs to `stg_gcs__rfx_opportunities` and `stg_gcs__rfx_sme_directory`.

Gcs Rfx Sme Directory

staging.stg_gcs__rfx_sme_directory
stagingbuild 1d agotests 15/15 passing2 PII columnsdata-eng@example.com
accessOperator only

SME directory, typed.

Cleaned mirror of `raw_gcs.rfx_sme_directory`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. The name/email columns are tagged PII so masking + erasure fire end-to-end. SMEs own opportunities and lead-author proposals.

Gcs Whse Approval Rules

staging.stg_gcs__whse_approval_rules
stagingbuild 1d agotests 15/15 passingdata-eng@example.com
accessOperator only

Approval-workflow rules, typed.

Cleaned mirror of `raw_gcs.whse_approval_rules`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. Reference data describing the approval workflow that gates warehousing operations on write-off value, hazmat handling, credit notes, and SLA waivers — no personal data.

Gcs Whse Clients

staging.stg_gcs__whse_clients
stagingbuild 1d agotests 16/16 passing2 PII columnsdata-eng@example.com
accessOperator only

Brand tenants, typed — the multi-tenant key.

Cleaned mirror of `raw_gcs.whse_clients`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. `client_id` is the multi-tenant isolation key propagated downstream. The primary_contact_name/email columns are tagged PII so masking + erasure fire end-to-end; account_manager_name is an internal label, not PII.

Gcs Whse Consignees

staging.stg_gcs__whse_consignees
stagingbuild 1d agotests 7/7 passing6 PII columnsdata-eng@example.com
accessOperator only

B2C recipients, typed — the primary DSR subject.

Cleaned mirror of `raw_gcs.whse_consignees`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. Carries identity (full_name), contact (email/phone), and location (address_line/city/postal_code) PII keyed to `consignee_id`, all tagged so masking + erasure fire end-to-end. Never surfaces raw via the AI layer. `country` is coarse and not PII on its own.

Gcs Whse Contracts

staging.stg_gcs__whse_contracts
stagingbuild 1d agotests 16/16 passingdata-eng@example.com
accessOperator only

Client×site contracts and SLA targets, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_contracts`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces FKs to `stg_gcs__whse_clients` and `stg_gcs__whse_sites`. Raw term dates are `start_date`/`end_date` (aliased to `term_start`/`term_end` only in `int_whse__contract_sla`; the corpus reads the raw names). The `source_uri` is the reconciliation key into the client-sla-contracts corpus.

Gcs Whse Inventory

staging.stg_gcs__whse_inventory
stagingbuild 1d agotests 15/15 passingdata-eng@example.com
accessOperator only

Stock positions by lot, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_inventory`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces FKs to `stg_gcs__whse_products` and `stg_gcs__whse_sites`. `client_id` is denormalized from the product owner and hardened by an INC-22 integrity test so the row policy on mart_inventory_health stays sound.

Gcs Whse Order Lines

staging.stg_gcs__whse_order_lines
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

Order lines and pick accuracy, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_order_lines`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces FKs to `stg_gcs__whse_orders` and `stg_gcs__whse_products`. Aggregated into mart_fulfillment_daily → metric_pick_accuracy. An INC-22 integrity test hardens tenant isolation: a line's SKU must belong to the parent order's client.

Gcs Whse Orders

staging.stg_gcs__whse_orders
stagingbuild 1d agotests 25/25 passingdata-eng@example.com
accessOperator only

Outbound fulfillment spine, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_orders`. Coerces the CSV's `Nullable(String)` columns into typed equivalents, derives `ship_month` via `toStartOfMonth(ship_date)`, and enforces FKs to `stg_gcs__whse_clients`, `stg_gcs__whse_sites`, and `stg_gcs__whse_consignees`. `client_id` is the row-policy key propagated to mart_order_outcomes. `dest_region` is the ship-to region, distinct from the site-derived `site_region` dimension.

Gcs Whse Permissions

staging.stg_gcs__whse_permissions
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

The warehousing RBAC matrix, typed.

Cleaned mirror of `raw_gcs.whse_permissions`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. Reference data describing intended access policy for the warehousing personas — no personal data. The client_account_manager rows document-as-data the client-scoped row policy actually enforced by governance.client_grants + getSetting('SQL_client_identity').

Gcs Whse Products

staging.stg_gcs__whse_products
stagingbuild 1d agotests 16/16 passingdata-eng@example.com
accessOperator only

Client SKU catalog, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_products`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces the FK to `stg_gcs__whse_clients` (the owning brand). `source_uri` is null for non-hazardous SKUs and set to the safety-data-sheets URI for `hazard_class != 'none'`.

Gcs Whse Returns

staging.stg_gcs__whse_returns
stagingbuild 1d agotests 12/12 passingdata-eng@example.com
accessOperator only

Returns, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_returns`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces the FK to `stg_gcs__whse_orders`. `client_id`/`site_id` are denormalized from the parent order; an INC-22 integrity test asserts the denormalized client_id equals the parent order's client_id. Feeds metric_returns_rate; `return_reason` → `reason` and `return_value_eur` → `return_value` on the mart.

Gcs Whse Sites

staging.stg_gcs__whse_sites
stagingbuild 1d agotests 21/21 passingdata-eng@example.com
accessOperator only

Warehouse network, typed.

Cleaned mirror of `raw_gcs.whse_sites`. Coerces the CSV's `Nullable(String)` columns into typed equivalents. The raw column is `region`; the mart/metric/ontology dimension `site_region` is a coalesced alias of it. Certification state is the three UInt8 flags (cert_gdp / cert_iso27001 / cert_hazmat) — no `certifications` string or `temp_capabilities` column exists.

Gcs Whse Staff

staging.stg_gcs__whse_staff
stagingbuild 1d agotests 14/14 passing2 PII columnsdata-eng@example.com
accessOperator only

Warehouse workforce, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_staff`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces the FK to `stg_gcs__whse_sites`. `units_per_labor_hr` rolls up into mart_site_performance.avg_units_per_labor_hr. The full_name/email columns are tagged PII so masking + erasure fire end-to-end.

Gcs Whse Temperature Events

staging.stg_gcs__whse_temperature_events
stagingbuild 1d agotests 8/8 passingdata-eng@example.com
accessOperator only

Cold-chain excursions, typed and FK-validated.

Cleaned mirror of `raw_gcs.whse_temperature_events`. Coerces the CSV's `Nullable(String)` columns into typed equivalents and enforces the FK to `stg_gcs__whse_inventory`. Staging-only in P0/P1 — cold-chain compliance is reached via catalog/BI preview + search_documents, not query_metric/query_records. Retention anchor: legal_obligation, 1825 days (GDP ~5yr).

Postgres Addresses

staging.stg_postgres__addresses
stagingbuild 1d agotests 6/6 passing6 PII columnsdata-eng@example.com
accessOperator only

Addresses, typed and country-normalised.

Customer shipping/billing addresses staged for join with `stg_postgres__shipments`. `valid_from` / `valid_to` form the SCD-2 validity window so the resolver can isolate address history per customer; the address lines (`line1`, `line2`), `city`, `region`, `postal_code`, and `country` are tagged as location-PII so column grants strip them for AI personas.

Postgres Agents

staging.stg_postgres__agents
stagingbuild 1d agotests 7/7 passing2 PII columnssupport-eng@example.com
accessOperator only

Agents, deduped and typed.

Support agents staged from the operational DB — dedupes on `agent_id` keeping the most-recent Airbyte extract, lower-cases email, and exposes `hired_at` as a required date for staffing analytics. The agent dimension that powers ticket attribution.

Postgres Ap Payment Applications

staging.stg_postgres__ap_payment_applications
stagingbuild 1d agotests 6/6 passingdata-eng@example.com
accessOperator only

AP payment applications, cleaned.

Allocation rows tying AP payments to the vendor bills they settle.

6 of 6
Column
Description
Tests · PII
ap_payment_application_id
Primary key — UInt64.
2 tests
ap_payment_id
FK to `stg_postgres__ap_payments.ap_payment_id`. NOT NULL.
2 tests
vendor_bill_id
FK to `stg_postgres__vendor_bills.vendor_bill_id`. NOT NULL.
applied_amount
Amount applied to this bill. Decimal(12,2).
source_created_at
Row insert timestamp from the source DB. DateTime64(6).
airbyte_extracted_at
When the loader extracted this row from postgres-source.
6 tests declaredmodels/staging/postgres_finance/stg_postgres__ap_payment_applications.sql
Open in lineage graph

Postgres Ap Payments

staging.stg_postgres__ap_payments
stagingbuild 1d agotests 11/11 passingdata-eng@example.com
accessOperator only

AP payments, cleaned.

AP payment events with txn vs functional amounts and realized FX gain/loss posted on settlement.

Postgres Approvals

staging.stg_postgres__approvals
stagingbuild 1d agotests 7/7 passingdata-eng@example.com
accessOperator only

Approvals, cleaned.

Approval workflow steps over finance objects. `object_type` + `object_id` is a polymorphic soft FK — no hard relationship test is possible; coverage is asserted via accepted_values on object_type + decision. `approver_employee_id` is an actor reference.

Postgres Ar Receipt Applications

staging.stg_postgres__ar_receipt_applications
stagingbuild 1d agotests 6/6 passingdata-eng@example.com
accessOperator only

AR receipt applications, cleaned.

Allocation rows tying AR receipts to the customer invoices they settle.

6 of 6
Column
Description
Tests · PII
ar_receipt_application_id
Primary key — UInt64.
2 tests
ar_receipt_id
FK to `stg_postgres__ar_receipts.ar_receipt_id`. NOT NULL.
2 tests
customer_invoice_id
FK to `stg_postgres__customer_invoices.customer_invoice_id`. NOT NULL.
2 tests
applied_amount
Amount applied to this invoice. Decimal(12,2).
source_created_at
Row insert timestamp from the source DB. DateTime64(6).
airbyte_extracted_at
When the loader extracted this row from postgres-source.
6 tests declaredmodels/staging/postgres_finance/stg_postgres__ar_receipt_applications.sql
Open in lineage graph

Postgres Ar Receipts

staging.stg_postgres__ar_receipts
stagingbuild 1d agotests 11/11 passingdata-eng@example.com
accessOperator only

AR receipts, cleaned.

AR cash receipts per customer with `source_payment_id` linkage back to the operational payments capture (so a customer DSAR reaches matched bank lines — H4).

Postgres Audit Log

staging.stg_postgres__audit_log
stagingbuild 1d agotests 4/4 passing2 PII columnsdata-eng@example.com
accessOperator only

Finance audit trail, cleaned.

Append-only change history. `old_value` / `new_value` may echo PII; retained under legal_obligation and erased via `retain_aggregate` (the history is itself the legal record). `object_id` is a soft FK keyed by object_type; `actor_employee_id` is an actor reference. Cursor on audit_log_id (no updated_at).

Postgres Bank Accounts

staging.stg_postgres__bank_accounts
stagingbuild 1d agotests 8/8 passingdata-eng@example.com
accessOperator only

Bank accounts, cleaned.

Bank-account dimension mapped to its GL cash account; drives AP/AR cash and reconciliations.

Postgres Bank Transactions

staging.stg_postgres__bank_transactions
stagingbuild 1d agotests 5/5 passing1 PII columndata-eng@example.com
accessOperator only

Bank transactions, cleaned.

Bank-statement lines with settlement linkage so a customer/vendor DSAR reaches matched lines (H4). `counterparty_name` is incidental financial PII (nullify on erasure).

5 tests declaredmodels/staging/postgres_finance/stg_postgres__bank_transactions.sql
Open in lineage graph

Postgres Bill Lines

staging.stg_postgres__bill_lines
stagingbuild 1d agotests 6/6 passing1 PII columndata-eng@example.com
accessOperator only

Vendor-bill lines, cleaned.

GL-coded AP line items with tax breakout. `description` may echo incidental PII (nullify on erasure).

Postgres Budgets

staging.stg_postgres__budgets
stagingbuild 1d agotests 4/4 passingdata-eng@example.com
accessOperator only

Budgets, cleaned.

Budget headers per (fiscal_year, version). status walks draft → approved → archived.

Postgres Chat Channels

staging.stg_postgres__chat_channels
stagingbuild 1d agotests 6/6 passing1 PII columndata-eng@example.com
accessOperator only

Chat channels, cleaned.

Chat-channel headers (Slack/Teams). `topic` is free-text PII (nullify on erasure). 365-day comms retention.

Postgres Chat Messages

staging.stg_postgres__chat_messages
stagingbuild 1d agotests 8/8 passing1 PII columndata-eng@example.com
accessOperator only

Chat messages, cleaned.

Chat messages authored by finance employees. `body_text` is free-text PII (nullify on erasure); the full body also lands in the GCS corpus at source_uri.

Postgres Cost Centers

staging.stg_postgres__cost_centers
stagingbuild 1d agotests 6/6 passingdata-eng@example.com
accessOperator only

Cost centers, cleaned.

The cost-center hierarchy typed for MergeTree marts. Parent FK builds the rollup tree; owner FK names the accountable manager.

Postgres Customer Invoices

staging.stg_postgres__customer_invoices
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

Customer invoices, cleaned.

AR invoice headers per customer (reusing the ecommerce customer + order). Open balance (`total_amount` - `amount_received`) ties to the AR control account.

10 tests declaredmodels/staging/postgres_finance/stg_postgres__customer_invoices.sql
Open in lineage graph

Postgres Customers

staging.stg_postgres__customers
stagingbuild 1d agotests 15/15 passing3 PII columnsdata-eng@example.com
accessOperator only

Customers, cleaned for MergeTree.

Customers staged from the operational DB — Airbyte's `Nullable(...)` wrapper stripped on PK and date columns so MergeTree marts can use them as keys, email lower-cased and trimmed, country normalised to ISO-2 uppercase. The canonical customer dimension feeding every customer-keyed mart.

Postgres Depreciation Schedule

staging.stg_postgres__depreciation_schedule
stagingbuild 1d agotests 5/5 passingdata-eng@example.com
accessOperator only

Depreciation schedule, cleaned.

Depreciation rows per (fixed_asset, period) — period depreciation, accumulated, and net book value.

5 tests declaredmodels/staging/postgres_finance/stg_postgres__depreciation_schedule.sql
Open in lineage graph

Postgres Email Message Participants

staging.stg_postgres__email_message_participants
stagingbuild 1d agotests 6/6 passing2 PII columnsdata-eng@example.com
accessOperator only

Email participants, cleaned.

Per-message recipients. The party may be an employee, customer, or vendor (mutually-exclusive Nullable FKs set by party_type). participant_email + display name are contact PII (nullify on erasure).

6 tests declaredmodels/staging/postgres_finance/stg_postgres__email_message_participants.sql
Open in lineage graph

Postgres Email Messages

staging.stg_postgres__email_messages
stagingbuild 1d agotests 10/10 passing4 PII columnsdata-eng@example.com
accessOperator only

Emails, cleaned.

Email messages with inline `body_text` (full body also lands in the GCS corpus at source_uri; document_id/sha256 backfilled). subject / body_text / sender_email / sender_display_name are PII (nullify on erasure). 365-day comms retention.

Postgres Email Threads

staging.stg_postgres__email_threads
stagingbuild 1d agotests 7/7 passing1 PII columndata-eng@example.com
accessOperator only

Email threads, cleaned.

Email-thread headers owned by a finance employee. `subject` is free-text PII (nullify on erasure). 365-day comms retention. Authoritative entity links live in communication_links.

Postgres Events

staging.stg_postgres__events
stagingbuild 1d agotests 5/5 passing2 PII columnsdata-eng@example.com
accessOperator only

What customers did on the website, typed.

Web event log staged from the operational DB. Carries behavioral PII (`page_url` may embed query-string identifiers; `session_id` is an online identifier under GDPR Art. 4(1)). Short retention (90 days). Not yet consumed by a mart — staged so the source declaration is no longer dangling and an engagement-funnel mart can build on it.

Postgres Expense Report Lines

staging.stg_postgres__expense_report_lines
stagingbuild 1d agotests 7/7 passing2 PII columnsdata-eng@example.com
accessOperator only

Expense-report lines, cleaned.

GL-coded expense lines per report. `merchant_name` + `description` are behavioral PII (nullify on erasure).

7 tests declaredmodels/staging/postgres_finance/stg_postgres__expense_report_lines.sql
Open in lineage graph

Postgres Expense Reports

staging.stg_postgres__expense_reports
stagingbuild 1d agotests 9/9 passing1 PII columndata-eng@example.com
accessOperator only

Expense reports, cleaned.

Expense-report headers submitted by employees. `report_title` can echo behavioral PII (nullify on erasure). Statutory record kept 7 years.

Postgres Finance Employees

staging.stg_postgres__finance_employees
stagingbuild 1d agotests 12/12 passing5 PII columnsdata-eng@example.com
accessOperator only

The finance team, cleaned.

Employee master for the `employee` data subject. work_email lowercased; identity / contact / financial PII tagged so masking fires downstream. DSAR erasure tokenizes identity here (per H6), not the retained legal_obligation rows that merely reference an employee.

12 tests declaredmodels/staging/postgres_finance/stg_postgres__finance_employees.sql
Open in lineage graph

Postgres Finance Notes

staging.stg_postgres__finance_notes
stagingbuild 1d agotests 7/7 passing2 PII columnsdata-eng@example.com
accessOperator only

Finance notes, cleaned.

Notes (meeting / close-checklist / reconciliation / board-prep / variance-commentary / general). `title` + `body_text` are free-text PII (nullify on erasure); the full body also lands in the GCS corpus.

Postgres Fixed Assets

staging.stg_postgres__fixed_assets
stagingbuild 1d agotests 12/12 passingdata-eng@example.com
accessOperator only

Fixed assets, cleaned.

Fixed-asset register naming the GL asset + accumulated-depreciation accounts; the source of the depreciation schedule.

Postgres Forecast Lines

staging.stg_postgres__forecast_lines
stagingbuild 1d agotests 9/9 passingdata-eng@example.com
accessOperator only

Forecast lines, cleaned.

Forecast detail rows per account / cost center / period.

Postgres Forecasts

staging.stg_postgres__forecasts
stagingbuild 1d agotests 6/6 passingdata-eng@example.com
accessOperator only

Forecasts, cleaned.

Forecast headers per (fiscal_year, scenario, version). scenario is base / upside / downside.

Postgres Fx Rates

staging.stg_postgres__fx_rates
stagingbuild 1d agotests 3/3 passingdata-eng@example.com
accessOperator only

FX rates, cleaned.

Spot / average / closing rates by date used to translate transaction amounts to functional USD.

8 of 8
Column
Description
Tests · PII
fx_rate_id
Primary key — UInt64.
2 tests
from_currency
Source currency (ISO-4217, uppercased).
to_currency
Target currency (uppercased, default USD).
rate_date
Date the rate applies to. Date.
rate_type
Rate basis — spot / average / closing.
1 test
rate
Conversion rate. Decimal(18,8).
source_created_at
Row insert timestamp from the source DB. DateTime64(6).
airbyte_extracted_at
When the loader extracted this row from postgres-source.

Postgres Gl Accounts

staging.stg_postgres__gl_accounts
stagingbuild 1d agotests 17/17 passingdata-eng@example.com
accessOperator only

The chart of accounts, cleaned.

GL accounts typed for MergeTree marts. Control accounts are the AR/AP balances subledgers must tie to.

Postgres Gl Journal Entries

staging.stg_postgres__gl_journal_entries
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

Journal-entry headers, cleaned.

One row per journal entry. `created_by_employee_id` is an actor reference (DSAR-access location, not a maskable identity column). Statutory record kept 7 years.

10 tests declaredmodels/staging/postgres_finance/stg_postgres__gl_journal_entries.sql
Open in lineage graph

Postgres Gl Journal Lines

staging.stg_postgres__gl_journal_lines
stagingbuild 1d agotests 7/7 passingdata-eng@example.com
accessOperator only

Double-entry GL lines, cleaned.

Line-level GL postings in functional USD. The exactly-one-of-debit/credit invariant (source CHECK) is re-asserted here as a dbt_utils.expression_is_true data test; trial-balance ties are tested downstream.

Postgres Invoice Lines

staging.stg_postgres__invoice_lines
stagingbuild 1d agotests 6/6 passingdata-eng@example.com
accessOperator only

Customer-invoice lines, cleaned.

GL-coded AR line items with tax breakout, optionally tied to an ecommerce product.

Postgres Marketing Campaigns

staging.stg_postgres__marketing_campaigns
stagingbuild 1d agotests 4/4 passingmarketing-eng@example.com
accessOperator only

Campaigns, with day-truncated send time.

Campaign-level metadata — channel, audience segment, optional promo. Joined to `stg_postgres__marketing_sends` on `campaign_id` for engagement-funnel marts. No per-customer rows here, so non-PII at the model level.

4 tests declaredmodels/staging/postgres_ecommerce/stg_postgres__marketing_campaigns.sql
Open in lineage graph

Postgres Marketing Sends

staging.stg_postgres__marketing_sends
stagingbuild 1d agotests 7/7 passing1 PII columnmarketing-eng@example.com
accessOperator only

Marketing touches with engagement funnel timestamps.

Per-customer touch from a marketing campaign. Seeder gates sends on the active consent state at send-time; mid-window consent withdrawals are NOT reflected here — for compliance reporting, pair with `mart_consent_current` instead of using this surface alone. Boolean flags (`is_delivered` etc.) are derived in `int_marketing_engagement`.

7 tests declaredmodels/staging/postgres_ecommerce/stg_postgres__marketing_sends.sql
Open in lineage graph

Postgres Order Items

staging.stg_postgres__order_items
stagingbuild 1d agotests 12/12 passingdata-eng@example.com
accessOperator only

Line-level detail behind every order, typed.

Per-line basket items staged from the operational DB. `unit_price` and `line_amount` are captured at order time (stable even when the catalog price changes later), so the model is the grain to use for a product-mix revenue breakdown rather than the order-total grain in `stg_postgres__orders`.

8 of 8
Column
Description
Tests · PII
order_item_id
Primary key — UInt64.
2 tests
order_id
FK to `stg_postgres__orders.order_id`. NOT NULL.
product_id
FK to `stg_postgres__products.product_id`. NOT NULL.
2 tests
quantity
Units purchased on this line. UInt32.
2 tests
unit_price
Per-unit price captured at order time. Decimal(10,2). Source-of-truth for revenue (may differ from current catalog price).
2 tests
line_amount
Line subtotal — `quantity * unit_price` materialised at write time. Decimal(12,2).
2 tests
source_created_at
Row insert timestamp from the source DB. DateTime64(6).
airbyte_extracted_at
When Airbyte extracted this row from postgres-source.

Postgres Order Promotions

staging.stg_postgres__order_promotions
stagingbuild 1d agotests 8/8 passingdata-eng@example.com
accessOperator only

Order ↔ promo bridge with captured discount.

Per-order promotion applications. `discount_amount` is the money taken off this order (computed from the promotion's discount_type / value at apply-time). One order may have multiple promos; (order_id, promotion_id) is unique. Drives `mart_promotion_performance`.

7 of 7
Column
Description
Tests · PII
order_promotion_id
Primary key — UInt64.
2 tests
order_id
FK to `stg_postgres__orders.order_id`. NOT NULL.
promotion_id
FK to `stg_postgres__promotions.promotion_id`. NOT NULL.
2 tests
discount_amount
Money taken off this order. Decimal(12,2).
2 tests
applied_at
When the promo was applied to the order. DateTime64(6).
applied_day
`toDate(applied_at)`. Convenience for daily marts.
airbyte_extracted_at
When Airbyte extracted this row from postgres-source.
8 tests declaredmodels/staging/postgres_ecommerce/stg_postgres__order_promotions.sql
Open in lineage graph

Postgres Orders

staging.stg_postgres__orders
stagingbuild 1d agotests 12/12 passingdata-eng@example.com
accessOperator only

Orders, with a derived day column.

Orders typed and joined-ready. Adds `order_day = toDate(order_at)` for use as a MergeTree partition / sort key downstream, and preserves the lifecycle `status` that defines "revenue-eligible" (everything except `cancelled` and `refunded`).

Postgres Payment Methods

staging.stg_postgres__payment_methods
stagingbuild 1d agotests 5/5 passing2 PII columnsdata-eng@example.com
accessOperator only

Payment methods, with soft-delete surfaced.

Per-customer payment instruments (cards, wallets, bank transfers). Soft-delete propagates as `is_active = deleted_at IS NULL` so downstream marts can filter without re-deriving. Raw PAN is never stored — `last4` + `card_brand` + `exp_*` are the only card fields and are tagged financial PII.

5 tests declaredmodels/staging/postgres_ecommerce/stg_postgres__payment_methods.sql
Open in lineage graph

Postgres Payments

staging.stg_postgres__payments
stagingbuild 1d agotests 8/8 passing1 PII columndata-eng@example.com
accessOperator only

Payment lifecycle rows, with a derived day column.

Per-order payment events — multiple rows per order are the norm (auth followed by capture; capture followed by refund). Revenue eligibility is `transaction_type='capture' AND status='succeeded'`; marts that sum `amount` blindly will double-count auth+capture. `processed_day` is the partition-friendly date for daily rollups.

Postgres Product Inventory Snapshots

staging.stg_postgres__product_inventory_snapshots
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

Inventory snapshots with derived availability.

Per-day stock position by product × warehouse. The unique constraint on the source means reseeds are deterministic; downstream marts can join freely on (product_id, warehouse_code, snapshot_date) without dedup. `available_qty` is materialised so stockout queries don't recompute.

10 tests declaredmodels/staging/postgres_ecommerce/stg_postgres__product_inventory_snapshots.sql
Open in lineage graph

Postgres Products

staging.stg_postgres__products
stagingbuild 1d agotests 12/12 passingdata-eng@example.com
accessOperator only

The catalog, with `name` renamed.

Products cleaned and re-keyed. Renames the SQL-reserved `name` column to `product_name`; otherwise a straight typed view of the catalog. The dimension every product-keyed mart joins to.

Postgres Promotions

staging.stg_postgres__promotions
stagingbuild 1d agotests 6/6 passingdata-eng@example.com
accessOperator only

Promotions, with active-window flag.

The promo / discount catalog. `discount_type` ∈ {percent, flat, free_shipping}; `discount_value` is the percent (5–30), the flat dollar amount, or 0 for free-shipping. `is_window_open` derives from `ends_at` for live-eligibility filters.

Postgres Reconciliation Items

staging.stg_postgres__reconciliation_items
stagingbuild 1d agotests 5/5 passingdata-eng@example.com
accessOperator only

Reconciliation items, cleaned.

Each item links a bank transaction and/or GL line to a reconciliation, or flags an unmatched / adjustment item.

5 tests declaredmodels/staging/postgres_finance/stg_postgres__reconciliation_items.sql
Open in lineage graph

Postgres Reconciliations

staging.stg_postgres__reconciliations
stagingbuild 1d agotests 7/7 passingdata-eng@example.com
accessOperator only

Reconciliations, cleaned.

One reconciliation per (bank_account, period). `difference_amount` is statement vs GL ending balance.

Postgres Recurring Journal Templates

staging.stg_postgres__recurring_journal_templates
stagingbuild 1d agotests 9/9 passingdata-eng@example.com
accessOperator only

Recurring-JE templates, cleaned.

Templates naming a debit + credit account, amount, frequency, and active period window; the source of accrual / deferral / prepaid postings.

9 tests declaredmodels/staging/postgres_finance/stg_postgres__recurring_journal_templates.sql
Open in lineage graph

Postgres Returns

staging.stg_postgres__returns
stagingbuild 1d agotests 14/14 passingdata-eng@example.com
accessOperator only

One row per return, typed and day-bucketed.

The typed returns ledger. `return_status` runs requested → approved → received → refunded (or rejected); `refund_amount` is non-zero only once `refunded`, so return-rate analytics must distinguish requested volume from realised refunds. `return_day` (toDate of requested_at) is the partition-friendly date for daily rollups.

Postgres Shipments

staging.stg_postgres__shipments
stagingbuild 1d agotests 6/6 passing1 PII columndata-eng@example.com
accessOperator only

Shipments with day-truncated milestones.

Per-order shipment rows with lifecycle timestamps. `shipped_at`, `estimated_delivery_at`, and `delivered_at` are all Nullable — `label_created` shipments haven't shipped; in-transit shipments haven't been delivered. SLA derivations belong in `int_shipments__sla` so this layer stays close to the source.

Postgres Subscriptions

staging.stg_postgres__subscriptions
stagingbuild 1d agotests 11/11 passing1 PII columndata-eng@example.com
accessOperator only

Subscriptions, with monthly-normalised amount.

One row per subscription. `monthly_amount` is already normalised on the source — annual plans store the monthly pro-rated value, so MRR aggregates that sum `monthly_amount` correctly count recurring revenue without re-amortising. Status transitions (`active` → `paused` / `cancelled` / `expired`) drive churn.

Postgres Support Tickets

staging.stg_postgres__support_tickets
stagingbuild 1d agotests 9/9 passing1 PII columnsupport-eng@example.com
accessOperator only

Tickets, with resolution metrics pre-computed.

Cleaned support-ticket headers. Pre-computes `resolution_hours`, `is_closed`, and `is_high_priority` so the daily mart doesn't recompute them. Carries customer and agent FKs for joins; the subject line is left tagged as PII and excluded from AI personas via column grants.

9 tests declaredmodels/staging/postgres_ecommerce/stg_postgres__support_tickets.sql
Open in lineage graph

Postgres Ticket Events

staging.stg_postgres__ticket_events
stagingbuild 1d agotests 5/5 passing1 PII columnsupport-eng@example.com
accessOperator only

Ticket lifecycle events, ready for rollup.

Per-ticket event stream typed and joined-ready. Adds `event_day = toDate(event_ts)` for daily rollups; comment payloads in `notes` are flagged as behavioral PII so column grants and erasure paths fire on them.

Postgres Vendor Bills

staging.stg_postgres__vendor_bills
stagingbuild 1d agotests 10/10 passingdata-eng@example.com
accessOperator only

Vendor bills, cleaned.

AP bill headers with txn vs functional totals. Open balance (`total_amount` - `amount_paid`) ties to the AP control account.

Postgres Vendors

staging.stg_postgres__vendors
stagingbuild 1d agotests 7/7 passing7 PII columnsdata-eng@example.com
accessOperator only

Vendors, cleaned.

Vendor master for the `vendor` data subject. Contact / financial / location PII tagged so masking fires downstream; the identity surface a vendor DSAR erases.

Unstructured Document Chunks

staging.stg_unstructured__document_chunks
stagingbuild skippedtests 4 declared1 PII columndata-eng@example.com
accessOperator only

Chunks, typed — the embedding worker's input.

Cleaned mirror of `raw_unstructured.document_chunks`. Coerces IDs to UUID/UInt32 and validates the FK to `stg_unstructured__documents`. The mart adds the embedding column and the HNSW index on top.

8 of 8
Column
Description
Tests · PII
document_id
FK to stg_unstructured__documents.
chunk_seq
0-based position. Unique within a document.
1 test
chunk_text
Paragraph-shaped chunk text. Soft cap ~512 tokens.
1 testPII
section
Heading path resolved for this chunk. Nullable.
page_start
First page this chunk's content appears on.
page_end
Last page this chunk's content appears on.
source_file_url
Airbyte-supplied `_ab_source_file_url`.
airbyte_extracted_at
When Airbyte extracted this row from GCS.

Unstructured Documents

staging.stg_unstructured__documents
stagingbuild skippedtests 8 declared2 PII columnsdata-eng@example.com
accessOperator only

Documents, typed.

Cleaned mirror of `raw_unstructured.documents`. Same column set as the raw layer, but with proper UUID/DateTime/LowCardinality types and a derived `extracted_day` for time-partitioned MergeTree downstream. PII columns inherit their full meta from the source layer.

source

Where the data starts

96 entries

Tables exactly as we receive them from operational systems (Postgres, GCS files). We don't query these directly from BI or AI — they exist so we can rebuild everything below from a single, faithful copy.

raw_gcs

Mdt Approval Rules

raw_gcs.mdt_approval_rules
sourcetests 2 failing
accessOperator only

Proposal routing + approval rules.

The config table for how a proposal moves through review, escalation, and issuance — one row per rule keyed by rule_id.

1 of 1
Column
Description
Tests · PII
rule_id
UUID5 — primary key. Stable across re-syncs.
2 tests

Mdt Contacts

raw_gcs.mdt_contacts
sourcetests 2 failing
accessOperator only

Buyer-side contacts on each opportunity.

One row per client contact named in the RFQ/correspondence for an opportunity. Carries identity PII (name/email/phone).

3 of 3
Column
Description
Tests · PII
contact_id
UUID5 — primary key. Stable across re-syncs.
full_name
Contact full name. Identity PII; erased via nullify.
email
Contact email. Contact PII; erased via nullify.

Mdt Devices

raw_gcs.mdt_devices
sourcetests 2 failing
accessOperator only

Devices under test on each opportunity.

The device dimension — one row per device under test, keyed by device_id, with the short nickname (PFS-NSD, OBI, AI) that joins to test methods and pricing line items.

1 of 1
Column
Description
Tests · PII
device_id
UUID5 — primary key. Stable across re-syncs.
2 tests

Mdt Historical Matches

raw_gcs.mdt_historical_matches
sourcetests 2 failing
accessOperator only

Similarity edges to past jobs.

One row per (opportunity, matched past job) similarity edge with a 0–100 score and a one-sentence relevance note.

1 of 1
Column
Description
Tests · PII
match_id
UUID5 — primary key. Stable across re-syncs.
2 tests

Mdt Opportunities

raw_gcs.mdt_opportunities
sourcetests 2 failing
accessOperator only

One RFQ opportunity per Smithers job reference.

The opportunity dimension for the testing-services domain — one row per Smithers job reference (e.g. 24-1005376HG), with client, region, entity, study type, and the RFQ→submission date chain.

6 of 6
Column
Description
Tests · PII
opportunity_id
UUID5 — primary key on the source side. Stable across re-syncs.
reference_id
Smithers job reference, verbatim (e.g. 24-1005376HG).
client_name
Client legal entity name. Confidential-commercial (GSK, Kashiv, Ypsomed).
bdm_lead
Smithers commercial/BDM lead. Identity PII; erased via nullify.
te_lead
Smithers technical lead. Identity PII; erased via nullify.
pm_lead
Smithers project-manager lead. Identity PII; erased via nullify.

Mdt Pricing Line Items

raw_gcs.mdt_pricing_line_items
sourcetests 2 failing
accessOperator only

Cost line items per device per proposal.

The pricing breakdown — one row per cost-generating activity, whose amounts sum to the proposal's total_rom. rate/amount are confidential-commercial.

2 of 2
Column
Description
Tests · PII
line_item_id
UUID5 — primary key. Stable across re-syncs.
2 tests
amount
Line cost. Confidential-commercial.

Mdt Proposals

raw_gcs.mdt_proposals
sourcetests 2 failing
accessOperator only

One issued/historical proposal per row.

One row per proposal responding to an opportunity — status, entity, currency, base ROM (ex-VAT ex-contingency), review path, and the request→issued cycle time. total_rom is confidential-commercial.

5 of 5
Column
Description
Tests · PII
proposal_id
UUID5 — primary key. Stable across re-syncs.
total_rom
Base ROM ex-VAT ex-contingency. Confidential-commercial.
bdm_lead
Smithers commercial/BDM lead. Identity PII; erased via nullify.
te_lead
Smithers technical lead. Identity PII; erased via nullify.
pm_lead
Smithers project-manager lead. Identity PII; erased via nullify.

Mdt Rate Card

raw_gcs.mdt_rate_card
sourcetests 2 failing
accessOperator only

Per-test rate card (GBP pence).

One row per (test name, category) — related_test (canonical family or raw-name alias), canonical_test, is_canonical, category (labour/setup/materials), and unit_rate_minor (GBP pence). Synthetic reference data generated by scripts/mdt/build_rate_card.py.

1 of 1
Column
Description
Tests · PII
rate_card_id
UUID5 — primary key. Stable across re-syncs.
2 tests

Mdt Rfps

raw_gcs.mdt_rfps
sourcetests 2 failing
accessOperator only

Incoming RFP intake pipeline.

One row per incoming RFP/RFQ in the intake queue — client, region, entity, channel, requested devices/tests, target dates, and the intake status (received/qualifying/quoted/declined/on_hold).

4 of 4
Column
Description
Tests · PII
rfp_id
UUID5 — primary key. Stable across re-syncs.
client_name
Client/prospect legal entity. Confidential-commercial.
budget_indication
Client-stated budget indication. Confidential-commercial.
bdm_owner
Smithers BDM owning the intake. Identity PII; erased via nullify.

Mdt Sme Directory

raw_gcs.mdt_sme_directory
sourcetests 2 failing
accessOperator only

Smithers subject-matter experts.

One row per named Smithers SME — role, site, entity, domain, and peer-review/escalation flags. Carries identity PII (name/email/phone).

3 of 3
Column
Description
Tests · PII
sme_id
UUID5 — primary key. Stable across re-syncs.
sme +3 PII2 tests
full_name
SME full name. Identity PII; erased via nullify.
email
SME work email. Contact PII; erased via nullify.

Mdt Standards

raw_gcs.mdt_standards
sourcetests 2 failing
accessOperator only

Testing standards catalog.

One row per standard referenced across the testing programmes, with its family and a source_uri to the full-text PDF.

1 of 1
Column
Description
Tests · PII
standard_id
UUID5 — primary key. Stable across re-syncs.
2 tests

Mdt Test Methods

raw_gcs.mdt_test_methods
sourcetests 2 failing
accessOperator only

Tests requested per device.

One row per (device, test) — the technical scope behind a proposal, carrying the cited standards and replicate plan.

1 of 1
Column
Description
Tests · PII
test_method_id
UUID5 — primary key. Stable across re-syncs.
2 tests

Product Reviews

raw_gcs.product_reviews
sourcetests 36/36 passing2 PII columns
accessOperator only

What customers said about products, and how strongly.

Raw customer × product reviews landed as CSV in GCS. One row per submitted review — rating, free-text body, helpful-vote count, and a verified-purchase flag arrive together before any cleanup. Staging coerces the CSV's String columns into typed equivalents and FK-validates against the e-commerce dimensions.

Rfx Accounts

raw_gcs.rfx_accounts
sourcetests 20/20 passing
accessOperator only

The organisations that issue RFXs to us.

The account dimension for the procurement domain — one row per buying organisation with industry, region, segment, tier, and a revenue band. The source of truth for every account-keyed opportunity and proposal downstream. No personal data: an account is a company, not a natural person (its contacts live in `rfx_contacts`).

8 of 8
Column
Description
Tests · PII
account_id
UUID5 — primary key on the source side. Stable across re-syncs.
2 tests
account_name
Human-readable company name (Faker company). Free-text.
industry
Vertical the account operates in. Coerced to LowCardinality(String) in staging.
region
Sales region — `NA`, `EMEA`, `APAC`, `LATAM`.
segment
Account size segment — `enterprise`, `mid`, `smb`.
tier
Strategic importance — `strategic`, `key`, `standard`.
annual_revenue_band
Bucketed annual revenue (e.g. `$50-250M`). Banded so no exact figure is stored.
created_at
ISO-8601 UTC timestamp the account record was created. Parsed in staging into `created_at` + derived `created_day`.

Rfx Approval Rules

raw_gcs.rfx_approval_rules
sourcetests 18/18 passing
accessOperator only

The thresholds that force a proposal into approval.

The approval-rule catalog — one row per rule with a trigger type, a threshold + comparator, the approver role, the sequence in the chain, an escalation role, and an SLA. Reference data describing the approval workflow for proposals — no personal data.

Rfx Contacts

raw_gcs.rfx_contacts
sourcetests 9/9 passing3 PII columns
accessOperator only

The people we deal with at each buying organisation.

One row per buyer-side contact at a procurement account — name, job title, email, phone, and a primary-contact flag. Carries identity PII (name/email/phone) keyed to `contact_id`; the PII columns are tagged so the manifest-driven masking + erasure rules fire end-to-end. FK-validated against `rfx_accounts` in staging.

8 of 8
Column
Description
Tests · PII
contact_id
UUID5 — primary key on the source side. Stable across re-syncs.
account_id
Account this contact belongs to. String on the wire (CSV); coerced and validated against `rfx_accounts` in staging.
full_name
Contact full name. Identity PII; erased via `nullify`.
PII
title
Job title at the buying organisation. Free-text, not classified as PII on its own.
email
Contact email address. Contact PII; erased via `nullify`.
PII
phone
Contact phone number. Contact PII; erased via `nullify`.
PII
is_primary
String "true"/"false" — set to "true" for the account's primary contact. Coerced to UInt8 (0/1) in staging.
created_at
ISO-8601 UTC timestamp the contact record was created. Parsed in staging.

Rfx Opportunities

raw_gcs.rfx_opportunities
sourcetests 29/29 passing
accessOperator only

Every RFX we have been invited to respond to.

One row per RFX opportunity — type (RFP/RFQ/RFI), account, region, issued/due dates, estimated value, pipeline stage, owning SME, and win probability. The spine of the procurement domain: proposals hang off it, and each opportunity reconciles with exactly one `rfx-documents` blob via the deterministic `source_uri`.

Rfx Permissions

raw_gcs.rfx_permissions
sourcetests 12/12 passing
accessOperator only

Who may do what to which procurement resource.

The RBAC matrix declaring, per RFX role, which actions are allowed or denied on each resource type and within what scope. Reference data describing intended access policy for the procurement personas — no personal data.

6 of 6
Column
Description
Tests · PII
permission_id
UUID5 — primary key on the source side. Stable across re-syncs.
2 tests
role
RFX role the rule applies to — `rfx_manager`, `rfx_contributor`, `rfx_approver`.
resource_type
Resource the rule governs — `opportunity`, `proposal`, `pricing`, `sme`, `document_corpus`.
action
Action the rule governs — `read`, `write`, `approve`, `export`.
effect
Whether the rule grants or denies — `allow`, `deny`.
scope_filter
Scope expression bounding the rule (e.g. `region='NA'`, or `*` for all). Free-text.

Rfx Price Book

raw_gcs.rfx_price_book
sourcetests 17/17 passing
accessOperator only

The guardrails on what we can quote, by region and segment.

The price book — one row per SKU per region per segment with a region/segment-adjusted list price, a floor price (≥ implied cost), a target margin, and a maximum discount. The source of truth for the pricing guardrails enforced when assembling a proposal.

Rfx Products Services

raw_gcs.rfx_products_services
sourcetests 17/17 passing
accessOperator only

The things we sell — the quotable catalog.

The product/service catalog for the procurement domain — one row per SKU with category, unit of sale, list price, unit cost, and an active flag. The source of truth for SKU names referenced by the price book; `unit_cost` is always below `list_price`.

Rfx Proposals

raw_gcs.rfx_proposals
sourcetests 16/16 passing
accessOperator only

What we proposed, for how much, and how it landed.

One row per proposal version against an opportunity — submitted / decision dates, outcome, total price + cost + margin, lead author, evaluation score, and the competitor we faced. Won and lost proposals reconcile with a `historical-proposals` blob via `source_uri`; pending/withdrawn ones carry no document.

Rfx Sme Directory

raw_gcs.rfx_sme_directory
sourcetests 17/17 passing2 PII columns
accessOperator only

Our experts — who can staff and author what.

One row per internal subject-matter expert — name, email, department, expertise + certification tags, seniority, weekly capacity, and availability. Carries identity PII (name/email) keyed to `sme_id`; the PII columns are tagged so masking + erasure fire end-to-end. SMEs own opportunities and lead-author proposals.

Whse Approval Rules

raw_gcs.whse_approval_rules
sourcetests 17/17 passing
accessOperator only

The thresholds that force an operation into approval.

The approval-rule catalog — one row per rule with a trigger type, a threshold + comparator, the approver role, the sequence in the chain, an escalation role, and an SLA. Reference data describing the approval workflow for warehousing operations (write-off value, hazmat handling, credit note, SLA waiver) — no personal data.

Whse Clients

raw_gcs.whse_clients
sourcetests 18/18 passing2 PII columns
accessOperator only

The brand tenants whose goods we warehouse.

The client dimension for the warehousing domain — one row per brand tenant with segment, tier, home region/country, and a primary contact. `client_id` is the multi-tenant isolation key carried onto every client-keyed table (orders, inventory, returns) and the target of the client_account_manager row policy. The primary-contact name/email are identity/contact PII tagged so masking + erasure fire end-to-end; account_manager_name is an internal role label, not PII.

Whse Consignees

raw_gcs.whse_consignees
sourcetests 9/9 passing6 PII columns
accessOperator only

B2C delivery recipients (consumer PII).

One row per B2C delivery recipient — the primary GDPR data subject for the DSR/erasure demo. Carries identity (full_name), contact (email/phone), and location (address_line/city/postal_code) PII keyed to `consignee_id`, all tagged so masking + erasure fire end-to-end. Never surfaces raw via the AI layer (mart_order_outcomes de-identifies). `country` is coarse and not PII on its own.

Whse Contracts

raw_gcs.whse_contracts
sourcetests 18/18 passing
accessOperator only

Client×site engagements and their SLA targets.

One row per client×site contract with billing model, OTIF / pick-accuracy / dock-to-stock SLA targets, term dates, auto-renew flag, and a monthly fee. Feeds int_whse__contract_sla → mart_client_scorecard. Every row carries a deterministic `source_uri` reconciliation key into the `client-sla-contracts` corpus. Raw term dates are `start_date`/`end_date` (aliased to `term_start`/`term_end` only in the intermediate; the corpus reads the raw names).

Whse Inventory

raw_gcs.whse_inventory
sourcetests 17/17 passing
accessOperator only

Live stock positions, by lot.

One row per lot with SKU, site, denormalized client owner, lot code, on-hand/allocated quantities, storage zone, bin location, received date, lot expiry (null for non-perishable), inventory status, and snapshot unit cost. Feeds int_whse__inventory_valued → mart_inventory_health. `client_id` is denormalized from the product owner so the row policy has a direct column.

Whse Order Lines

raw_gcs.whse_order_lines
sourcetests 12/12 passing
accessOperator only

Line-level picks and pick accuracy.

One row per order line with the parent order, SKU, line number, units ordered/picked, pick time, unit price, and accuracy / short-pick flags. Aggregated into mart_fulfillment_daily (accurate_lines, total_lines) → metric_pick_accuracy. A line's SKU is always drawn from the parent order's client catalog (INC-22 integrity test).

Whse Orders

raw_gcs.whse_orders
sourcetests 27/27 passing
accessOperator only

The outbound fulfillment spine.

One row per order with client, site, consignee, order/promised/ ship/delivered dates, derived `ship_month`, carrier, destination country/region, status, order value, denormalized line count and units, and precomputed OTIF flags (is_on_time / is_in_full / is_otif). The table the isolation gate reads via mart_order_outcomes. `dest_region` is the ship-to region — a distinct column from the site-derived `site_region` dimension.

Whse Permissions

raw_gcs.whse_permissions
sourcetests 12/12 passing
accessOperator only

Who may do what to which warehousing resource.

The RBAC matrix declaring, per logistics role, which actions are allowed or denied on each resource type and within what scope. Reference data describing intended access policy for the warehousing personas — no personal data. The client_account_manager rows document-as-data the client-scoped row policy actually enforced by governance.client_grants + getSetting('SQL_client_identity').

6 of 6
Column
Description
Tests · PII
permission_id
UUID5 — primary key on the source side. Stable across re-syncs.
2 tests
role
Logistics role the rule applies to — `logistics_ops_manager`, `client_account_manager`, `logistics_ai_analyst`, `compliance_officer`.
resource_type
Resource the rule governs — `order`, `inventory`, `contract`, `site`, `consignee`, `document_corpus`.
action
Action the rule governs — `read`, `write`, `approve`, `export`.
effect
Whether the rule grants or denies — `allow`, `deny`.
scope_filter
Scope expression bounding the rule (e.g. `client_id=own_client_grant`, `region='EU'`, `*`). Free-text.

Whse Products

raw_gcs.whse_products
sourcetests 18/18 passing
accessOperator only

The client-owned SKU catalog.

One row per SKU with owning client, category, temp class, hazard class, value band, per-unit value, weight/volume, units per pallet, and shelf life. Drives cold-chain and SDS. Hazardous SKUs carry a `safety-data-sheets` `source_uri`; non-hazardous SKUs write an empty string (→ null in staging).

Whse Returns

raw_gcs.whse_returns
sourcetests 14/14 passing
accessOperator only

Returns disposition and cycle time.

One row per return against a delivered order with denormalized client + site, return date, disposition, reason, units returned, return value, cycle time, and a restocked flag. Row-detail concept `return_case` via mart_returns; feeds metric_returns_rate. `return_reason` is aliased to `reason` and `return_value_eur` to `return_value` on the mart. `client_id` is denormalized from the parent order (INC-22 integrity test).

Whse Sites

raw_gcs.whse_sites
sourcetests 23/23 passing
accessOperator only

The physical warehouse network.

The site dimension for the warehousing domain — one row per warehouse across the EU/UK/NA/APAC network with type, automation, capacity, and three certification flags (GDP / ISO27001 / hazmat). The raw column is `region`; the mart/metric/ontology dimension `site_region` is a coalesced alias of it. No `certifications` string or `temp_capabilities` column exists — cert state is the three UInt8 flags.

Whse Staff

raw_gcs.whse_staff
sourcetests 16/16 passing2 PII columns
accessOperator only

The warehouse workforce.

One row per staff member with assigned site, function, shift, employment type, productivity (units_per_labor_hr), hire date, and active flag. Site-level averages roll up into mart_site_performance.avg_units_per_labor_hr. Carries identity (full_name) and contact (email) PII keyed to `staff_id`, tagged so masking + erasure fire end-to-end.

Whse Temperature Events

raw_gcs.whse_temperature_events
sourcetests 10/10 passing
accessOperator only

Cold-chain excursion records.

One row per temperature excursion against a chilled/frozen lot with denormalized site + client, start/end timestamps, min/max/ threshold temperatures, duration, disposition, and a resolved-within-SLA flag. Staging-only in P0/P1 — cold-chain compliance is reached via catalog/BI preview + search_documents, not query_metric/query_records. Retention anchor: legal_obligation, 1825 days (GDP ~5yr).

raw_postgres

Addresses

raw_postgres.addresses
sourcetests 9/9 passing6 PII columns
accessOperator only

Where to ship and bill — per customer.

Per-customer postal addresses with a validity window (`valid_from` / `valid_to`). Source of truth for the ship-to address joined into `shipments`. Address-line + city + region + postal code are location-PII; column-level grants strip them for AI personas.

Agents

raw_postgres.agents
sourcetests 12/12 passing2 PII columns
accessOperator only

The humans handling support tickets.

Support agent roster — identity, team tier, tenure. Joins to `support_tickets` on `agent_id`. Agents are a separate data subject from customers; their PII is governed under `processing_purpose: support` rather than the consumer consent ledger.

8 of 8
Column
Description
Tests · PII
agent_id
Primary key — BIGSERIAL on the source.
agent PII2 tests
email
Agent work email. Unique on the source; treated as PII downstream.
2 testsPII
full_name
Agent display name shown in tickets.
PII
team
Tier the agent works on — one of `tier1`, `tier2`, `specialist`, `manager`.
1 test
hired_at
Date the agent was hired. Used to bound staffing analytics.
is_active
True for currently employed agents; false for departures (kept for historical ticket attribution).
created_at
Row insert timestamp in the source DB.
updated_at
Row update timestamp in the source DB.

Ap Payment Applications

raw_postgres.ap_payment_applications
sourcetests 10/10 passing
accessOperator only

Which payment cleared which bill, and for how much.

Allocation rows tying AP payments to vendor bills. Grain (ap_payment_id, vendor_bill_id) UNIQUE on the source — sums to the vendor's settled balance.

5 of 5
Column
Description
Tests · PII
ap_payment_application_id
Primary key — BIGSERIAL on the source.
2 tests
ap_payment_id
FK to `ap_payments.ap_payment_id`. NOT NULL.
1 test
vendor_bill_id
FK to `vendor_bills.vendor_bill_id`. NOT NULL.
applied_amount
Amount of the payment applied to this bill. NUMERIC(12,2).
created_at
Row insert timestamp in the source DB.

Ap Payments

raw_postgres.ap_payments
sourcetests 19/19 passing
accessOperator only

Money we paid out to vendors.

AP payment events per vendor, with txn vs functional amounts and realized FX gain/loss posted when bill and payment rates differ. Statutory record kept 7 years.

Approvals

raw_postgres.approvals
sourcetests 12/12 passing
accessOperator only

Who approved what, and when.

Approval workflow steps over finance objects (`object_type` + `object_id` is a polymorphic soft FK; no hard relationship test). `approver_employee_id` is an actor reference (DSAR-access location).

Ar Receipt Applications

raw_postgres.ar_receipt_applications
sourcetests 10/10 passing
accessOperator only

Which receipt cleared which invoice, and for how much.

Allocation rows tying AR receipts to customer invoices. Grain (ar_receipt_id, customer_invoice_id) UNIQUE on the source.

5 of 5
Column
Description
Tests · PII
ar_receipt_application_id
Primary key — BIGSERIAL on the source.
2 tests
ar_receipt_id
FK to `ar_receipts.ar_receipt_id`. NOT NULL.
1 test
customer_invoice_id
FK to `customer_invoices.customer_invoice_id`. NOT NULL.
1 test
applied_amount
Amount of the receipt applied to this invoice. NUMERIC(12,2).
created_at
Row insert timestamp in the source DB.

Ar Receipts

raw_postgres.ar_receipts
sourcetests 19/19 passing
accessOperator only

Money customers paid us.

AR cash receipts per customer, with `source_payment_id` linkage back to the operational payments capture (so a customer DSAR reaches matched bank lines deterministically — H4). Statutory record kept 7 years.

Audit Log

raw_postgres.audit_log
sourcetests 7/7 passing2 PII columns
accessOperator only

The tamper-evident change history for finance objects.

Append-only audit trail. `old_value` / `new_value` may echo PII; they are retained under legal_obligation and erased via `retain_aggregate` (the change history is itself the legal record, so values are aggregated, never nullified). Cursor is on audit_log_id (no updated_at).

Bank Accounts

raw_postgres.bank_accounts
sourcetests 11/11 passing
accessOperator only

The bank accounts we move cash through.

One row per bank account, mapped to its GL cash account. Drives AP payments, AR receipts, bank transactions, and reconciliations.

Bank Transactions

raw_postgres.bank_transactions
sourcetests 9/9 passing1 PII column
accessOperator only

Cash movements on the bank statement.

Bank-statement lines with settlement linkage (source_payment_id / ar_receipt_id / ap_payment_id) so a customer/vendor DSAR reaches matched lines deterministically (H4). `counterparty_name` is incidental financial PII (nullify on erasure). Statutory record kept 7 years.

Bill Lines

raw_postgres.bill_lines
sourcetests 10/10 passing1 PII column
accessOperator only

Line-level detail behind every vendor bill.

GL-coded AP line items with tax breakout. `description` can echo incidental personal data, so it is nullify-on-erasure. Statutory record kept 7 years.

Budget Lines

raw_postgres.budget_lines
sourcetests 15/15 passing
accessOperator only

Budgeted amount per account / cost center / period.

Budget detail rows. Grain (budget, gl_account, cost_center, period) UNIQUE on the source — the budget side of budget-vs-actuals.

8 of 8
Column
Description
Tests · PII
budget_line_id
Primary key — BIGSERIAL on the source.
2 tests
budget_id
FK to `budgets.budget_id`. NOT NULL.
1 test
gl_account_id
FK to `gl_accounts.gl_account_id`. NOT NULL.
1 test
cost_center_id
FK to `cost_centers.cost_center_id`. NOT NULL.
1 test
period_id
FK to `fiscal_periods.period_id` (not staged in this slice). NOT NULL.
1 test
budget_amount
Budgeted amount. NUMERIC(14,2).
created_at
Row insert timestamp in the source DB.
updated_at
Row update timestamp in the source DB.

Budgets

raw_postgres.budgets
sourcetests 7/7 passing
accessOperator only

The annual budget versions.

Budget headers per (fiscal_year, version) — UNIQUE on the source. `status` walks draft → approved → archived.

Chat Channels

raw_postgres.chat_channels
sourcetests 11/11 passing1 PII column
accessOperator only

The finance chat channels.

Chat-channel headers (Slack/Teams). `topic` is free-text PII (nullify on erasure). 365-day comms retention.

Chat Messages

raw_postgres.chat_messages
sourcetests 14/14 passing1 PII column
accessOperator only

Individual chat messages, with searchable bodies.

Chat messages authored by finance employees. `body_text` is free-text PII (nullify on erasure); the full body also lands in the GCS corpus at source_uri (document_id/sha256 backfilled). 365-day comms retention.

Cost Centers

raw_postgres.cost_centers
sourcetests 10/10 passing
accessOperator only

The org units we budget and post against.

Cost-center hierarchy used by GL lines, budgets, forecasts, and expense lines. `parent_cost_center_id` builds the rollup tree; `owner_employee_id` names the accountable manager.

Customer Invoices

raw_postgres.customer_invoices
sourcetests 17/17 passing
accessOperator only

What we billed customers, and how much is still owed.

AR invoice headers per customer (reusing the ecommerce customer + order). `amount_received` vs `total_amount` drives the open-AR balance that ties to the AR control account. Statutory record kept 7 years.

Customers

raw_postgres.customers
sourcetests 31/31 passing3 PII columns
accessOperator only

Who has ever signed up to buy from us.

The operational customer table — one row per registered customer. Carries identity PII (email, names) plus segment and country attributes. The source of truth for every customer-keyed mart downstream; PII columns are tagged so the manifest-driven masking rules fire end-to-end.

Depreciation Schedule

raw_postgres.depreciation_schedule
sourcetests 9/9 passing
accessOperator only

How each asset depreciates, period by period.

Depreciation rows per (fixed_asset, period) — UNIQUE on the source. Carries period depreciation, accumulated depreciation, and net book value; the source of the recurring depreciation journal entries.

8 of 8
Column
Description
Tests · PII
depreciation_schedule_id
Primary key — BIGSERIAL on the source.
2 tests
fixed_asset_id
FK to `fixed_assets.fixed_asset_id`. NOT NULL.
1 test
period_id
FK to `fiscal_periods.period_id` (not staged in this slice). NOT NULL.
1 test
depreciation_amount
Depreciation for the period. NUMERIC(14,2).
accumulated_depreciation
Cumulative depreciation to date. NUMERIC(14,2).
net_book_value
Net book value after the period. NUMERIC(14,2).
journal_entry_id
FK to the GL entry that posted the depreciation. Nullable.
created_at
Row insert timestamp in the source DB.

Email Message Participants

raw_postgres.email_message_participants
sourcetests 11/11 passing2 PII columns
accessOperator only

Who was on each email (to / cc / bcc).

Per-message recipients. The party may be an employee, customer, or vendor (mutually-exclusive Nullable FKs set by party_type). participant_email + display name are contact PII (nullify on erasure). 365-day comms retention.

Email Messages

raw_postgres.email_messages
sourcetests 17/17 passing4 PII columns
accessOperator only

Individual emails, with searchable inline bodies.

Email messages with inline `body_text` (full body also lands in the GCS corpus at source_uri; document_id/sha256 backfilled from the corpus manifest). subject / body_text / sender_email / sender_display_name are PII (nullify on erasure). 365-day comms retention.

Email Threads

raw_postgres.email_threads
sourcetests 12/12 passing1 PII column
accessOperator only

Email threads owned by a finance mailbox.

Email-thread headers owned by a finance employee. `subject` is free-text PII (nullify on erasure). Comms retention is 365 days under legitimate_interest. Authoritative entity links live in communication_links.

Events

raw_postgres.events
sourcetests 39/39 passing2 PII columns
accessOperator only

What customers did on the website.

Web event log — page views, add-to-cart, checkout funnel. Carries behavioral PII (`page_url` may include query-string identifiers; `session_id` is an online identifier under GDPR Art. 4(1)). Short retention (90 days). Not yet consumed by staging — kept available for future engagement-funnel marts.

8 of 8
Column
Description
Tests · PII
event_id
Primary key — BIGSERIAL on the source.
2 tests
customer_id
FK to `customers.customer_id`. Nullable for anonymous sessions.
event_type
Event kind — `page_view`, `add_to_cart`, `checkout_start`, `checkout_complete`.
event_ts
Time the event fired (TIMESTAMPTZ).
page_url
Page where the event was emitted. May contain query-string identifiers — treat as behavioral PII.
PII
product_id
FK to `products.product_id` when the event relates to a product (e.g. `add_to_cart`). Nullable.
session_id
Opaque session identifier — joins events fired within a single browsing session. Online identifier under GDPR Art. 4(1).
PII
created_at
Row insert timestamp in the source DB.

Expense Report Lines

raw_postgres.expense_report_lines
sourcetests 12/12 passing2 PII columns
accessOperator only

Line-level detail behind every expense report.

GL-coded expense lines per report. `merchant_name` + `description` are behavioral PII (nullify on erasure). Statutory record kept 7 years.

Expense Reports

raw_postgres.expense_reports
sourcetests 16/16 passing1 PII column
accessOperator only

Employee expense claims and their lifecycle.

Expense-report headers submitted by employees. `report_title` can echo behavioral PII (nullify on erasure). Statutory record kept 7 years (basis legal_obligation per OQ-2 / C1).

Finance Employees

raw_postgres.finance_employees
sourcetests 16/16 passing5 PII columns
accessOperator only

The finance team — who they are and who they report to.

Employee master for the finance domain. The identity table for the `employee` data subject (DSAR erasure tokenizes identity here, not the retained legal_obligation rows that merely reference an employee). Carries contact + financial PII; `manager_employee_id` builds the reporting tree.

Finance Notes

raw_postgres.finance_notes
sourcetests 13/13 passing2 PII columns
accessOperator only

Working notes the finance team writes.

Notes (meeting / close-checklist / reconciliation / board-prep / variance-commentary / general). `title` + `body_text` are free-text PII (nullify on erasure); the full body also lands in the GCS corpus at source_uri. 365-day comms retention.

Fiscal Periods

raw_postgres.fiscal_periods
sourcetests none declared
accessOperator only
About this source

One row per fiscal period — period_code (e.g. FY2025-M07), fiscal year/month, start/end dates, and close status (open / closed / locked).

Fixed Assets

raw_postgres.fixed_assets
sourcetests 21/21 passing
accessOperator only

The capitalised assets we depreciate.

Fixed-asset register with acquisition cost, salvage, useful life, and the GL asset + accumulated-depreciation accounts. Source of the depreciation schedule.

Forecast Lines

raw_postgres.forecast_lines
sourcetests 15/15 passing
accessOperator only

Forecasted amount per account / cost center / period.

Forecast detail rows. Grain (forecast, gl_account, cost_center, period) UNIQUE on the source.

8 of 8
Column
Description
Tests · PII
forecast_line_id
Primary key — BIGSERIAL on the source.
2 tests
forecast_id
FK to `forecasts.forecast_id`. NOT NULL.
1 test
gl_account_id
FK to `gl_accounts.gl_account_id`. NOT NULL.
1 test
cost_center_id
FK to `cost_centers.cost_center_id`. NOT NULL.
1 test
period_id
FK to `fiscal_periods.period_id` (not staged in this slice). NOT NULL.
1 test
forecast_amount
Forecasted amount. NUMERIC(14,2).
created_at
Row insert timestamp in the source DB.
updated_at
Row update timestamp in the source DB.

Forecasts

raw_postgres.forecasts
sourcetests 11/11 passing
accessOperator only

The forecast scenarios.

Forecast headers per (fiscal_year, scenario, version) — UNIQUE on the source. `scenario` is base / upside / downside; `status` walks draft → published → archived.

Fx Rates

raw_postgres.fx_rates
sourcetests 6/6 passing
accessOperator only

Exchange rates for currency translation.

Spot / average / closing FX rates by date. UNIQUE on (from_currency, to_currency, rate_date, rate_type). Monetary rows reference an fx_rate_id to compute their functional-USD amount.

7 of 7
Column
Description
Tests · PII
fx_rate_id
Primary key — BIGSERIAL on the source.
2 tests
from_currency
Source currency (ISO-4217, normalised uppercase).
to_currency
Target currency (defaults to `USD`).
rate_date
Date the rate applies to.
rate_type
Rate basis — `spot` / `average` / `closing`.
1 test
rate
Conversion rate. NUMERIC(18,8).
created_at
Row insert timestamp in the source DB.

Gl Accounts

raw_postgres.gl_accounts
sourcetests 23/23 passing
accessOperator only

The chart of accounts.

One row per GL account — code, name, type/subtype, normal balance. Control accounts are the AR/AP balances the subledgers must tie to (subledger_ties_to_gl invariant).

Gl Journal Entries

raw_postgres.gl_journal_entries
sourcetests 18/18 passing
accessOperator only

The journal-entry headers behind every GL posting.

One row per journal entry — period, entry date, source, status, and the employee who created it (`created_by_employee_id` is an actor reference, a DSAR-access location). Statutory record kept 7 years.

Gl Journal Lines

raw_postgres.gl_journal_lines
sourcetests 11/11 passing
accessOperator only

The debit/credit lines that make every entry balance.

Line-level GL postings in functional USD. Exactly one of `debit_amount` / `credit_amount` is non-zero per line (source CHECK; re-asserted in staging tests). Sum(debit)=Sum(credit) per entry and per period (trial_balance_zero_per_period).

Invoice Lines

raw_postgres.invoice_lines
sourcetests 10/10 passing
accessOperator only

Line-level detail behind every customer invoice.

GL-coded AR line items with tax breakout, optionally tied to an ecommerce product. Statutory record kept 7 years.

Marketing Campaigns

raw_postgres.marketing_campaigns
sourcetests 7/7 passing
accessOperator only

Outbound campaigns and their audience.

Campaign-level metadata — channel, audience segment, optional promo code distributed via the campaign. Joined to `marketing_sends` for per-customer engagement. `name` is renamed to `campaign_name` downstream to avoid the SQL keyword.

7 of 7
Column
Description
Tests · PII
campaign_id
Primary key — BIGSERIAL.
2 tests
name
Campaign display name (renamed to `campaign_name` downstream).
channel
`email` / `push` / `sms`.
1 test
audience_segment
Cohort slug — `all` / `consumer` / `business` / `enterprise` / `inactive_30d`. Nullable.
promotion_id
FK to `promotions.promotion_id`. Nullable.
send_at
When the campaign sent. TIMESTAMPTZ.
created_at
Row insert timestamp in the source DB.

Marketing Sends

raw_postgres.marketing_sends
sourcetests 11/11 passing1 PII column
accessOperator only

Marketing touches — sent, opened, clicked, unsubscribed.

Per-customer marketing touch with the engagement funnel timestamps (`sent_at` → `delivered_at` → `opened_at` → `clicked_at`, or `unsubscribed_at` / `bounce_reason` on the negative path). Seeder gates on the active consent state at send-time; for live compliance reporting, pair this surface with `mart_consent_current` rather than relying on it alone.

Order Items

raw_postgres.order_items
sourcetests 18/18 passing
accessOperator only

Line-level detail behind every order.

Per-line basket items for each order — quantity × unit_price captured at order time (so the figure is stable even if the catalog price changes later). The grain when a revenue question needs a product-mix breakdown rather than an order-total breakdown.

7 of 7
Column
Description
Tests · PII
order_item_id
Primary key — BIGSERIAL on the source.
2 tests
order_id
FK to `orders.order_id`. NOT NULL.
product_id
FK to `products.product_id`. NOT NULL.
1 test
quantity
Units purchased on this line.
unit_price
Per-unit price captured at order time. Source-of-truth for revenue (may differ from current catalog `products.unit_price`).
line_amount
Line subtotal — `quantity * unit_price` materialised at write time.
created_at
Row insert timestamp in the source DB.

Order Promotions

raw_postgres.order_promotions
sourcetests 12/12 passing
accessOperator only

Which promo was applied to which order, and for how much.

The order ↔ promotion bridge with the actual money taken off (`discount_amount`). Computed from the promotion's type+value at apply-time, so historical discounts remain stable even when the catalog row changes.

5 of 5
Column
Description
Tests · PII
order_promotion_id
Primary key — BIGSERIAL.
2 tests
order_id
FK to `orders.order_id`. NOT NULL. ON DELETE CASCADE.
promotion_id
FK to `promotions.promotion_id`. NOT NULL.
1 test
discount_amount
Money taken off this order. NUMERIC(12,2). Non-negative.
applied_at
When the promo was applied. TIMESTAMPTZ.

Orders

raw_postgres.orders
sourcetests 56/56 passing
accessOperator only

What was bought, when, and for how much.

The operational order header — one row per order. `total_amount` plus the lifecycle `status` (cancelled/refunded vs. revenue-eligible) feed every revenue rollup downstream. Cancellation and refunds are excluded from revenue by convention across all certified metrics.

8 of 8
Column
Description
Tests · PII
order_id
Primary key — BIGSERIAL on the source.
customer_id
FK to `customers.customer_id`. NOT NULL on the source.
order_date
Timestamp the order was placed (TIMESTAMPTZ). Renamed to `order_at` + derived `order_day` in staging.
status
Order lifecycle state. Revenue rollups exclude `cancelled` and `refunded`.
1 test
currency
ISO-4217 currency code of `total_amount`. Defaults to `USD`.
total_amount
Order grand total in `currency`. NUMERIC(12,2). Sums to revenue when status is a revenue state.
created_at
Row insert timestamp in the source DB.
updated_at
Row update timestamp in the source DB.

Payment Methods

raw_postgres.payment_methods
sourcetests 8/8 passing2 PII columns
accessOperator only

How customers pay — tokenised.

Per-customer tokenised payment instruments. `card_brand` + `last4` + `exp_*` are the only card fields, all tagged financial-PII; soft-delete via `deleted_at` (staging surfaces `is_active`). Used by every `payments` row to attribute transactions back to a method.

Payments

raw_postgres.payments
sourcetests 46/46 passing1 PII column
accessOperator only

Money in / money back per order.

Per-order payment event stream. One order may have multiple rows: an auth, then a capture, then optional refunds/voids. Revenue = `transaction_type='capture' AND status='succeeded'` — summing `amount` blindly double-counts auth+capture. Joined to `payment_methods` and `orders` downstream.

Product Inventory Snapshots

raw_postgres.product_inventory_snapshots
sourcetests 15/15 passing
accessOperator only

How much stock sits where, day by day.

Per-day stock position by product × warehouse. Unique constraint (product_id, warehouse_code, snapshot_date) means re-seeding is deterministic. Drives inventory-health metrics (stockout risk, days-of-cover, under-reorder count).

8 of 8
Column
Description
Tests · PII
snapshot_id
Primary key — BIGSERIAL.
2 tests
product_id
FK to `products.product_id`. NOT NULL.
1 test
warehouse_code
`us-west` / `us-east` / `eu-central`.
1 test
snapshot_date
Date the snapshot was taken.
1 test
on_hand_qty
Units physically on hand. Non-negative.
reserved_qty
Units allocated to in-flight orders. Non-negative.
reorder_point
Threshold below which a reorder fires.
created_at
Row insert timestamp in the source DB.

Products

raw_postgres.products
sourcetests 51/51 passing
accessOperator only

The catalog we sell from.

The operational product catalog — one row per SKU with category, list price, and an active flag. The source of truth for product names referenced everywhere downstream. `name` is renamed to `product_name` in staging to avoid the SQL keyword.

8 of 8
Column
Description
Tests · PII
product_id
Primary key — BIGSERIAL on the source.
2 tests
sku
Stock-keeping unit code. Unique business identifier surfaced in BI.
2 tests
name
Human-readable product name (renamed to `product_name` in staging to avoid the SQL keyword).
category
Product category (e.g. `electronics`, `apparel`). Loose taxonomy, may be null.
unit_price
Catalog list price in the product's reporting currency. NUMERIC(10,2).
is_active
True if the product is currently sellable; false for archived/deleted catalog entries.
created_at
Row insert timestamp in the source DB.
updated_at
Row update timestamp in the source DB.

Promotions

raw_postgres.promotions
sourcetests 22/22 passing
accessOperator only

Discount codes — the catalog.

The promo/discount catalog. `discount_type` is one of `percent`, `flat`, or `free_shipping`; `discount_value` encodes the percent (5–30), flat dollar amount, or 0. `max_redemptions` caps total usage.

Reconciliation Items

raw_postgres.reconciliation_items
sourcetests 9/9 passing
accessOperator only

The matched / unmatched items inside a reconciliation.

Each item links a bank transaction and/or a GL journal line to a reconciliation, or flags an unmatched / adjustment item.

8 of 8
Column
Description
Tests · PII
reconciliation_item_id
Primary key — BIGSERIAL on the source.
2 tests
reconciliation_id
FK to `reconciliations.reconciliation_id`. NOT NULL.
1 test
bank_transaction_id
FK to `bank_transactions.bank_transaction_id`. Nullable.
journal_line_id
FK to `gl_journal_lines.journal_line_id`. Nullable.
match_type
Match kind — `matched` / `unmatched_bank` / `unmatched_book` / `adjustment`.
1 test
amount
Item amount. NUMERIC(12,2).
note
Free-text note. Nullable.
created_at
Row insert timestamp in the source DB.

Reconciliations

raw_postgres.reconciliations
sourcetests 12/12 passing
accessOperator only

Bank-to-book reconciliation per account / period.

One reconciliation per (bank_account, period) — UNIQUE on the source. `difference_amount` is statement vs GL ending balance.

Recurring Journal Templates

raw_postgres.recurring_journal_templates
sourcetests 16/16 passing
accessOperator only

The templates that generate accrual / deferral entries.

Recurring-JE templates naming a debit + credit account, amount, frequency, and active period window. Source of accrual / deferral / prepaid postings.

Returns

raw_postgres.returns
sourcetests 64/64 passing
accessOperator only

What got sent back, why, and how much we refunded.

The operational returns ledger — one row per return request, linked to the order line it reverses. `return_status` tracks the lifecycle (requested → approved → received → refunded, or rejected); `refund_amount` is non-zero only once a return is `refunded`. Aggregated downstream into `mart_returns_daily` (de-identified by day × category × reason), which drops the customer linkage entirely.

Shipments

raw_postgres.shipments
sourcetests 23/23 passing1 PII column
accessOperator only

Where parcels go and how long they take.

Per-order shipment rows joined to `addresses` for the ship-to destination. Carries lifecycle status (`label_created` → `in_transit` → `delivered` / `returned` / `lost`) plus the three timestamps that drive SLA metrics. `tracking_number` is tagged behavioural-PII (carrier audit trail).

Subscriptions

raw_postgres.subscriptions
sourcetests 27/27 passing1 PII column
accessOperator only

Recurring plans the customer has on file.

Customer subscriptions. `plan_name` is the cadence (`monthly` / `quarterly` / `annual`), but `monthly_amount` is always normalised to a monthly figure on the source — so MRR aggregates sum it without re-amortising. Status transitions (`active` → `paused` / `cancelled` / `expired`) are the churn signal.

Support Tickets

raw_postgres.support_tickets
sourcetests 19/19 passing1 PII column
accessOperator only

Every customer issue we've worked.

One row per support ticket — lifecycle status, priority, agent assignment, optional CSAT score. The `subject` line is treated as behavioral PII (may quote customer wording). Resolution and first-response timestamps power queue-health metrics downstream.

Ticket Events

raw_postgres.ticket_events
sourcetests 8/8 passing1 PII column
accessOperator only

How each ticket moved through the queue.

Per-ticket event stream — open / assign / comment / status_change / csat_submitted / closed. Powers SLA timing and agent-handoff analytics. Comment payloads in `notes` are flagged as behavioral PII and hidden from AI personas via column grants.

8 of 8
Column
Description
Tests · PII
ticket_event_id
Primary key — BIGSERIAL on the source.
2 tests
ticket_id
FK to `support_tickets.ticket_id`. NOT NULL.
event_type
Event kind — `created`, `assigned`, `comment`, `status_change`, `csat_submitted`, `closed`.
actor_type
Who emitted the event — `customer`, `agent`, or `system`.
actor_id
Customer or agent id depending on `actor_type`. Null for `system` events.
event_ts
Time the event happened (TIMESTAMPTZ).
notes
Free-text payload (comment body, status transition note, etc.). Nullable.
PII
created_at
Row insert timestamp in the source DB.

Vendor Bills

raw_postgres.vendor_bills
sourcetests 17/17 passing
accessOperator only

What vendors billed us, and how much is still owed.

AP bill headers per vendor, with txn vs functional (`base_*`) totals. `amount_paid` vs `total_amount` drives the open-AP balance that ties to the AP control account. Statutory record kept 7 years.

Vendors

raw_postgres.vendors
sourcetests 14/14 passing7 PII columns
accessOperator only

Who we buy from and where we pay them.

Vendor master for the `vendor` data subject. Carries the primary-contact identity/contact, tax id, remit-to address, and bank last4. The identity surface a vendor DSAR erases.

raw_unstructured

Document Chunks

raw_unstructured.document_chunks
sourcetests 4 failing1 PII column
accessOperator only

Embedded chunks — the actual semantic-search surface.

One row per chunk. `chunk_text` is what the embedding worker consumes and what `search_documents` returns to AI traffic. `(document_id, chunk_seq)` is the natural key.

6 of 6
Column
Description
Tests · PII
document_id
FK → documents.document_id.
chunk_seq
0-based position in the DoclingDocument hierarchy. Stable across re-extracts.
1 test
chunk_text
Paragraph-shaped chunk text. Soft cap ~512 tokens.
1 testPII
section
Heading path Docling resolved for this chunk, if any. Nullable.
page_start
First page this chunk's content appears on. Nullable when Docling can't resolve a page.
page_end
Last page this chunk's content appears on. Nullable when Docling can't resolve a page.

Documents

raw_unstructured.documents
sourcetests 6 failing2 PII columns
accessOperator only

Docling-extracted documents — the index over our unstructured corpora.

One row per source binary (PDF / image / scan). Holds the extracted text, the extractor + pipeline that produced it (VLM vs EasyOCR), document language, page count, and a Presidio entity-count summary. The text is searchable via the chunks table downstream; this table is the catalog of what we have indexed.

observability

How the platform is doing

21 entries

Elementary's freshness, volume, and test outcomes on top of dbt's own metadata. Useful for incidents, not for product analysis.

Alerts Anomaly Detection

elementary.alerts_anomaly_detection
observabilitybuild 1d agotests none declared
accessOperator only
About this model

A view that is used by the Elementary CLI to generate alerts on data anomalies detected using the elementary anomaly detection tests. The view filters alerts according to configuration.

No documented columns. Run MAIVEN Transform to populate the catalog.

Alerts Dbt Models

elementary.alerts_dbt_models
observabilitybuild 1d agotests none declared
accessOperator only
About this model

A view that is used by the Elementary CLI to generate models alerts, including all the fields the alert will include such as owner, tags, error message, etc. It joins data about models and snapshots run results, and filters alerts according to configuration.

No documented columns. Run MAIVEN Transform to populate the catalog.

Alerts Dbt Tests

elementary.alerts_dbt_tests
observabilitybuild 1d agotests none declared
accessOperator only
About this model

A view that is used by the Elementary CLI to generate dbt tests alerts, including all the fields the alert will include such as owner, tags, error message, etc. This view includes data about all dbt tests except elementary tests. It filters alerts according to configuration.

No documented columns. Run MAIVEN Transform to populate the catalog.

Alerts Schema Changes

elementary.alerts_schema_changes
observabilitybuild 1d agotests none declared
accessOperator only
About this model

A view that is used by the Elementary CLI to generate alerts on schema changes detected using elementary tests. The view filters alerts according to configuration.

No documented columns. Run MAIVEN Transform to populate the catalog.

Anomaly Threshold Sensitivity

elementary.anomaly_threshold_sensitivity
observabilitybuild 1d agotests none declared
accessOperator only
About this model

This is a view on metrics_anomaly_score that calculates if values of metrics from latest runs would have been considered anomalies in different anomaly scores. This can help you decide if there is a need to adjust the anomaly_score_threshold.

No documented columns. Run MAIVEN Transform to populate the catalog.

Data Monitoring Metrics

elementary.data_monitoring_metrics
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Elementary anomaly detection tests monitor metrics such as volume, freshness and data quality metrics. This incremental table is used to store the metrics over time. On each anomaly detection test, the test queries this table for historical metrics, and compares to the latest values. The table is updated with new metrics on the on-run-end named handle_test_results that is executed at the end of dbt test invocations.

No documented columns. Run MAIVEN Transform to populate the catalog.

Dbt Exposures

elementary.dbt_exposures
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Metadata about exposures in the project, including configuration and properties from the dbt graph. Each row contains information about a single exposure. Data is loaded every time this model is executed. It is recommended to execute the model every time a change is merged to the project.

Dbt Invocations

elementary.dbt_invocations
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Attributes associated with each dbt invocation. Inserted at the end of each invocation.

Dbt Metrics

elementary.dbt_metrics
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Metadata about metrics in the project, including configuration and properties from the dbt graph. Each row contains information about a single metric. Data is loaded every time this model is executed. It is recommended to execute the model every time a change is merged to the project.

Dbt Models

elementary.dbt_models
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Metadata about models in the project, including configuration and properties from the dbt graph. Each row contains information about a single model. Data is loaded every time this model is executed. It is recommended to execute the model every time a change is merged to the project.

Dbt Run Results

elementary.dbt_run_results
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Run results of dbt invocations, inserted at the end of each invocation. Each row is the invocation result of a single resource (model, test, snapshot, etc). New data is loaded to this model on an on-run-end hook named 'elementary.upload_run_results' from each invocation that produces a result object. This is an incremental model.

Dbt Snapshots

elementary.dbt_snapshots
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Metadata about snapshots in the project, including configuration and properties from the dbt graph. Each row contains information about a single snapshot. Data is loaded every time this model is executed. It is recommended to execute the model every time a change is merged to the project.

Dbt Sources

elementary.dbt_sources
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Metadata about sources in the project, including configuration and properties from the dbt graph. Each row contains information about a single source. Data is loaded every time this model is executed. It is recommended to execute the model every time a change is merged to the project.

Dbt Tests

elementary.dbt_tests
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Metadata about tests in the project, including configuration and properties from the dbt graph. Each row contains information about a single test. Data is loaded every time this model is executed. It is recommended to execute the model every time a change is merged to the project.

Elementary Test Results

elementary.elementary_test_results
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Run results of all dbt tests, with fields and metadata needed to produce the Elementary report UI. Each row is the result of a single test, including native dbt tests, packages tests and elementary tests. New data is loaded to this model on an on-run-end hook named elementary.handle_tests_results.

No documented columns. Run MAIVEN Transform to populate the catalog.

Job Run Results

elementary.job_run_results
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Run results of dbt invocations, enriched with jobs metadata. Each row is the result of a single job. This is a view on dbt_invocations.

No documented columns. Run MAIVEN Transform to populate the catalog.

Metrics Anomaly Score

elementary.metrics_anomaly_score
observabilitybuild 1d agotests none declared
accessOperator only
About this model

This is a view on data_monitoring_metrics that runs the same query the anomaly detection tests run to calculate anomaly scores. The purpose of this view is to provide visibility to the results of anomaly detection tests.

No documented columns. Run MAIVEN Transform to populate the catalog.

Model Run Results

elementary.model_run_results
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Run results of dbt models, enriched with models metadata. Each row is the result of a single model. This is a view that joins data from dbt_run_results and dbt_models.

No documented columns. Run MAIVEN Transform to populate the catalog.

Monitors Runs

elementary.monitors_runs
observabilitybuild 1d agotests none declared
accessOperator only
About this model

This is a view on data_monitoring_metrics that is used to determine when a specific anomaly detection test was last executed. Each anomaly detection test queries this view to decide on a start time for collecting metrics.

No documented columns. Run MAIVEN Transform to populate the catalog.

Schema Columns Snapshot

elementary.schema_columns_snapshot
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Stores the schema details for tables that are monitored with elementary schema changes test. In order to compare current schema to previous state, we must store the previous state. The data is from a view that queries the data warehouse information schema. This is an incremental table.

No documented columns. Run MAIVEN Transform to populate the catalog.

Snapshot Run Results

elementary.snapshot_run_results
observabilitybuild 1d agotests none declared
accessOperator only
About this model

Run results of dbt snapshots, enriched with snapshots metadata. Each row is the result of a single snapshot. This is a view that joins data from dbt_run_results and dbt_snapshots.

No documented columns. Run MAIVEN Transform to populate the catalog.