# 01 — Suger CS Data Model (What a CSM Should Work Against)

**Owner:** Dico Angelo · **Scope:** Customer Success system-of-record for Suger

## Design principle

The data model is not the answer. **The capture gate is.** Every object below exists to serve one gate: *no account enters the CS motion without a dated contract, a tagged sentiment, and a named owner.* Miss the gate, every downstream dashboard, forecast, and renewal motion is guessing.

![Suger CS data model — 8 objects rolling up to a 5-pillar health score](diagrams/rendered/data-model-erd.webp)

## Object inventory (what I'd want in Suger)

### `Account` (existing)
The canonical customer record. Already in the dataset as `Customer #`.

| Field | Type | Purpose |
|---|---|---|
| `id` | Number | Unique identifier |
| `arr` | Currency | Source-of-truth for ARR (used in priority formula) |
| `is_active` | Boolean | Is the account currently consuming |
| `tenure_days` | Number | Days since onboarding — weighted into renewal signal |
| `owner__c` | Lookup(User) | **Named CSM** — required, never nullable |

### `Contract` (needs enforcement)
Already exists in the dataset — 95 of 316 accounts have no dated contract. **This is the biggest structural gap.**

| Field | Type | Purpose |
|---|---|---|
| `account_id` | Lookup(Account) | Scope |
| `start_date` / `end_date` | Date (required) | Renewal-stage trigger anchors |
| `days_to_renewal` | Formula | `end_date − TODAY()` — drives 90/60/30/0 stages |
| `has_contract` | Checkbox | Validation: FALSE blocks renewal-stage motion |
| `auto_renew` | Boolean | Distinguishes motion-required vs. silent-renewal |

Validation rule: no account may enter a renewal stage without a dated contract. Backfill sprint driven by AR/billing export closes the 95-record gap in Week 1.

### `Integration` (multi-record per Account)
The `marketplaces_integrated` count in the dataset. 41 accounts have zero — they paid and never shipped.

| Field | Type | Purpose |
|---|---|---|
| `account_id` | Lookup(Account) | Scope |
| `marketplace` | Picklist (AWS / GCP / Azure / Redhat / Snowflake / ...) | Which MP |
| `status` | Picklist (live / in-flight / blocked / abandoned) | Implementation state |
| `listing_go_live_date` | Date | Time-to-value metric anchor |

### `HealthSignal` (the capture layer — today's dark zone)
Today's dataset has one `sentiment` field, 75% unknown. This object is where CSM calls, Gong summaries, and product-usage signals land.

| Field | Type | Purpose |
|---|---|---|
| `account_id` | Lookup(Account) | Scope |
| `captured_at` | DateTime | Timeline of sentiment |
| `source` | Picklist (call / email / product / support_ticket) | Traceability |
| `sentiment` | Picklist (excellent / good / neutral / poor / unknown) | Primary signal |
| `summary_text` | Long text | AI-generated synopsis (Gong/Fathom auto-post) |
| `tags` | Multi-picklist (expansion / at-risk / blocker / champion / exec-departed) | Routing |

**This is the object that closes Finding #3.** Capture at source — Gong/Fathom webhooks post to Suger account timeline — not at month-end in a spreadsheet.

### `CosellOpp` (existing signal)
The `cosell_in_last_6_months` and `offers_last_6_months` columns. This is where Suger's private-offer and co-sell motion intersects with CS.

| Field | Type | Purpose |
|---|---|---|
| `account_id` | Lookup(Account) | Scope |
| `marketplace` | Picklist | Where the offer lives |
| `offer_amount` | Currency | Deal size |
| `status` | Picklist (draft / shared / accepted / closed_won / closed_lost) | Funnel stage |
| `trend_6mo` | Formula | Delta vs. prior 6mo — expansion signal |

### `Disbursement` (existing)
The `disburse_last_year` and `disburse_amount_last_6_months` columns. Money actually moving through Suger.

| Field | Type | Purpose |
|---|---|---|
| `account_id` | Lookup(Account) | Scope |
| `period` | Date | When |
| `amount` | Currency | $ disbursed |
| `trend` | Formula | Delta vs. prior period — growth signal |

### `Bug` (existing signal)
`num_of_bugs` is a count — the object behind it is what matters for quality.

| Field | Type | Purpose |
|---|---|---|
| `account_id` | Lookup(Account) | Scope |
| `severity` | Picklist | Quality-tax weight |
| `age_days` | Formula | Compounds into health penalty |
| `eng_owner` | Lookup(User) | Top-5 ARR accounts get named Eng bug-owner |

### `Maturity` (derived, but should be explicit)
The dataset has `maturity ∈ {Emerging, Scaling, Advanced}` — but the promotion rules are implicit. Make them explicit and automated.

| Field | Type | Rule |
|---|---|---|
| `Emerging` | — | Default. < 2 MPs or no cosell or no disbursement |
| `Scaling` | — | 2+ MPs live AND cosell motion live AND first disbursement hit |
| `Advanced` | — | 3+ MPs AND sustained disbursement trend positive AND health ≥ 60 |

Promotion event fires `MaturityChange` → triggers CSM playbook (new plays unlock at Scaling, exec-alignment at Advanced).

![Maturity ladder with declarative promotion gates](diagrams/rendered/maturity-ladder.webp)

## The 5-pillar health score

The dataset's `health_score` is a composite. I decomposed it into 5 pillars so the CSM can see *why* a score is low, not just *that* it is:

| Pillar | Weight | What it measures | Dataset column |
|---|---|---|---|
| **Adoption** | 25% | Marketplaces live, tenure, CRM connection | `s_adoption` |
| **Momentum** | 25% | Offers/cosell/disburse trend deltas | `s_momentum` |
| **Revenue** | 20% | ARR tier + disbursement volume | `s_revenue` |
| **Quality** | 15% | Bug count, bug age, severity | `s_quality` |
| **Renewal** | 15% | Days-to-renewal, contract presence, auto-renew | `s_renewal` |

A 32 health score on Adoption=15 / Renewal=20 is a different play than 32 on Quality=5 / Momentum=50. The pillars are the play-selector.

![5-pillar health score decomposition with weights](diagrams/rendered/health-pillars.webp)

## The priority formula

The dashboard's churn-risk ranking uses:

```
priority_score = risk_score × log(1 + ARR)
```

Why log-scaled ARR: a $50K account at 80% risk and a $5M account at 80% risk are not the same call. Log dampens the ARR dominance so small-but-dying accounts still surface, while large-but-dying accounts sit at the top. The top-20 list in the dashboard is sorted by this score.

## Why "Contract + Sentiment + Owner" is the gate

Without all three:
- **No contract** → no renewal trigger → account falls off the CS motion entirely (142 are past-due today).
- **No sentiment** → CSM has no signal between QBRs → risk is invisible until it's churn.
- **No owner** → no accountable human → every dashboard is correct-but-uncalled-on.

Every rule, every automation, every MCP agent in the AI-enablement stack is downstream of those three fields being populated. Name the gate before the rule.
