AGT-501 — Customer Health Monitor
Layer 5: Post-Sale Retention · Daily health scoring · 7 dimensions + ConvIntelligence adj + payment modifier · Canonical source for AGT-502 and AGT-503
L5 · Agent 01
Specced · v19 original + v25 ripple update
L8 ripple: seat utilization dimension reads UsageMeteringLog explicitly
L8 ripple update (v25)
Update — seat utilization dimension source: UsageMeteringLog
The seat utilization dimension (18 pts max) previously referenced "AGT-804 usage data feed" without specifying the schema table. UsageMeteringLog now exists as the canonical usage data source (added in v25 with AGT-804).
AGT-501 seat utilization dimension reads:
· UsageMeteringLog WHERE account_id = [account] AND sku_id LIKE 'SKU-SEAT%' AND period_end >= [trailing 30-day window]
· Utilization rate = units_consumed ÷ commit_units for the most recent complete metering period
· Score: >80% utilization = full points; 60–80% = partial; <60% = low utilization signal
Non-blocking dependency: if UsageMeteringLog has no records for this account (AGT-804 not live or seat SKU not metered), the seat utilization dimension is flagged as data_gap — same behavior as before. No change to scoring logic, only the explicit data source is now named.
Update — CSM call ConvIntelligence adjustment: call_owner_role filter
ConvIntelligence.call_owner_role field (added v23) enables AGT-501 to correctly filter CSM-owned calls for the ConvIntelligence adjustment (+12 pts max). AGT-501 reads ConvIntelligence WHERE account_id = [account] AND call_owner_role = 'CSM' AND call_date >= [trailing 30 days]. Selling-role calls (AE, SDR, SE) are excluded from this adjustment — they are not signals of customer health, only of deal activity.
Purpose
AGT-501 runs daily batch scoring for all active customer accounts. It writes CustomerHealthLog as the canonical daily record — AGT-502 (Churn Risk Detector) and AGT-503 (Expansion Trigger) read exclusively from this table. It is the single source of truth for account health across the post-sale stack.
Scoring model — 7 dimensions (100 pts base)
| Dimension | Max pts | Source | Notes |
| Product usage trend | 22 | UsageMeteringLog — consumption trend across trailing 3 periods | Trending up = full pts. Flat = partial. Declining = low pts. |
| Exec sponsor engagement | 20 | Contacts — economic_buyer and champion persona types | Persona-typed engagement from Contacts table (v18 L2 ripple pattern) |
| Seat utilization | 18 | UsageMeteringLog WHERE sku_id LIKE 'SKU-SEAT%' | Most recent complete period. Data_gap if no records. |
| NPS / CSAT | 14 | NPS/CSAT survey system (external feed) | No OnboardingLog proxy — data_gap during onboarding by design. |
| Engagement recency | 12 | ConvIntelligence, QBRLog, ABMEngagementLog | Days since last meaningful touchpoint across all channels. |
| Support ticket trend | 8 | Support system feed (external) | Volume + severity trend. Escalating tickets = lower score. |
| Competitive threat | 6 | ConvIntelligence.competitors_mentioned, CompetitiveKnowledgeBase | Active competitive evaluation signal. |
During onboarding (Accounts.onboarding_status = 'active'): AGT-501 substitutes OnboardingLog signals for dimensions where live data doesn't exist. Seat utilization, exec sponsor engagement, usage trend, and engagement recency all have defined OnboardingLog substitutes. Records flagged in_onboarding = TRUE in CustomerHealthLog.
Adjustments and modifiers (applied after 7-dimension base)
| Adjustment | Value | Source |
| ConvIntelligence adjustment | Up to +12 pts | ConvIntelligence WHERE call_owner_role = 'CSM' — trailing 30-day pattern of sentiment, talk ratio, next-step quality (v23) |
| Payment health modifier | Cap or floor | CustomerHealthLog.payment_health_status from AGT-803: Current = no effect; Overdue = cap at 77; Failed = cap at 62; Suspended = floor at Critical. Applied last. |
Key outputs — CustomerHealthLog fields
| Field | Notes |
raw_health_score | 7-dimension score + ConvIntelligence adjustment, before payment modifier |
health_score | Post-modifier final score. This is what AGT-502 and AGT-503 read. |
score_delta | Change from prior day. Used by AGT-502 for ≥15 pt drop alert. |
payment_health_status | Written by AGT-803. AGT-501 reads and applies modifier. |
sponsor_departure_flag | Passes to AGT-502 immediately on same run — does not wait for next AGT-502 cycle. |
in_onboarding | TRUE when Accounts.onboarding_status = 'active'. Signals OnboardingLog substitution mode. |
data_gap_dimensions | JSON array of dimensions scored as data_gap this run. |