Revenue confirms source tables, row grain, person_id derivation, and test data posture for the revenue silver face
Source tables in scope
The revenue silver face should cover the following tables from the revenue schema:
revenue_recognitions— the earned-revenue event table; primary grain for analyticsrevenue_attribution_entries— the per-order-item attribution slice, linking a recognition to its source order itemcredit_ledger_entries— the full credit transaction log; types includePURCHASE_CREDIT,LESSON_DEBIT,RESERVATION_LOCK_DEBIT,REFUND_DEBIT,CREDIT_FORFEIT,ADJUSTMENTordersandorder_items— commercial transactions and their line items;order_itemscarriescredits_recognized,revenue_recognized_total_cents, and snapshot pricing fieldscredit_reservations— reservation and lock state percredit-reservation-lockcontract; carriesstatus(RESERVED, LOCKED, CONSUMED, RELEASED, VOIDED, FORFEITED) andfunding_status(PENDING_FUNDING, FUNDED, REFUNDING, REFUNDED, NOT_APPLICABLE)refundsandrefund_items— refund lifecycle and per-item amounts
Tables that are Revenue-internal operational infrastructure and should not be exposed in the silver face: dispatcher_*, dispatcher_inbox_dedup, square_cutover_drift_log, webhook_events, webhook_deliveries, external_actions, order_externals, refund_externals, invoice_externals, invoices, client_profile_identity_bridges, client_external_identity_bridges, person_first_locks, provider_accounts, card_externals, organization_integrations, offerings, promotions, promotion_redemptions, clients.
Row grain
The primary grain for the revenue silver face is one row per revenue recognition event (revenue_recognitions). This is the GAAP-aligned earned-revenue fact: a recognition records the amount recognized, the period it was recognized in (recognition_period), whether it is a normal or contra entry, and links back to the source credit ledger entry, the triggering lesson, and the credit reservation.
Secondary grains that the silver face should expose as separate models:
- One row per credit ledger entry (
credit_ledger_entries) — the transaction grain for credit flow; Finance's reconciliation grouping will want this to tie period-level figures back to individual debit and credit movements. - One row per order (
orders) — the commercial-order grain; carriesstatus,amount_due_cents,amount_paid_cents, andpaid_at. - One row per credit reservation (
credit_reservations) — the lock-state grain; carries lock timestamps and funding state.
Person_id derivation
credit_accounts.person_id is a direct column that already carries the canonical Platform per_ Person ID per Identity Contract v1.1. It is the join anchor for all person-resolution on the revenue silver face.
Join paths from each primary table to person_id:
revenue_recognitions→source_credit_ledger_entry_id→credit_ledger_entries.credit_account_id→credit_accounts.person_idcredit_ledger_entries→credit_account_id→credit_accounts.person_idorders→client_id→credit_accounts.client_id(multiple credit accounts may exist per client; use thepaying_credit_account_idon the lesson, or join viacredit_reservations.credit_account_idif the resolution needs to be reservation-scoped)credit_reservations→credit_account_id→credit_accounts.person_id
The cleanest and most unambiguous path for the silver face is to resolve person_id through credit_reservations or credit_ledger_entries rather than through orders directly, since the credit account is the entity that carries the canonical identity link.
No lookup join against Platform's reverse-lookup endpoint is needed: credit_accounts.person_id is already populated as part of the CL-PLT-0002 cutover and contains per_ prefixed canonical IDs.
Test data posture
Revenue has no is_test_data boolean column in any table. The passthrough approach used for the growth and sales faces is acceptable; Revenue will not require a hard filter at the silver layer. Downstream consumers and the finance gold section can filter by organization_id (present on credit_reservations, lessons, order_items) against known test organization IDs if they need to exclude test records.
One note for Platform's dbt model: credit_ledger_entries carries a tenant_id column (nullable; populated on newer entries, null on legacy backfills). This is not an is-test flag but it does carry the tenancy context useful for multi-org scoping. Passing it through as a conformed column is correct; filtering on it is a gold-section concern.