Churn Risk is a module in Signal (Power Digital's internal BI web app) at route /predictions/churn, visible to Team Lead and above (base-tier Members are redirected away). It answers "which clients are at risk of leaving, why, and has anyone acted on it?" by showing every active client ranked by a 0–1 churn score from the AI/ML team's weekly churn model, with a drill-down Client 360 panel per client. Top-level data origins: the AI/ML churn model (scores and risk sub-scores), Vena finance actuals (MGP / MRR / VABO), nova contract data (retainer revenue, contract dates), Salesforce (opportunities), Gong (call sentiment), Client Pulse submissions entered in Signal, Anthropic Claude (AI-written summaries), Asana (task tracking), and Signal's own records (action triage, notes, and overrides entered by users in Signal).
Field | Value |
Route | /predictions/churn (deep link per client: /predictions/churn/:clientId) |
Access | Team Lead and above (route guard MemberAllowedRoute blocks base-tier Members; Team Lead, Admin, Gandalf, Sauron all pass) |
Nav section | "Client Health" → "Churn Risk" (Churn Risk is the section's default route) |
Primary data sources | AI/ML churn model (weekly scores), Vena finance actuals, nova contract data, Salesforce, Gong, Client Pulse (entered in Signal), Anthropic Claude (generated text), Signal's own records |
Writes | Signal's own records (action feedback, manual follow-ups, action notes, client notes, AI summaries, brand intel, usage events) + Asana (task creation) |
Key code refs | src/views/predictions/ChurnPredictionsView.tsx, ChurnOverviewTab.tsx, ChurnClientDetail.tsx, JourneySummary.tsx, recommendedActions.ts; server/predictions.ts, server/index.ts (/api/predictions/churn), server/journeySummary.ts, server/summaryPrompt.ts, server/brandIntel.ts, server/snapshotRecommendedActions.ts, server/snapshotClientSummaries.ts |
Last verified | staging @ 98df0c4, verified 2026-07-07 |
Purpose
The Churn Risk module in Signal exists so Power Digital discovers client unhappiness weeks before renewal, not at renewal. It consolidates scattered retention signals — contract timelines, invoice payment behavior, call sentiment from Gong, Client Pulse submissions, performance pacing, and Salesforce pipeline activity — into one composite churn score per client, produced weekly by the AI/ML team's churn model outside of Signal. The module answers three leadership questions: (1) where is revenue at risk right now (a ranked, dollar-weighted list), (2) why is a specific client at risk (score decomposition into Client Profile / Sentiment / Performance risk, rule-derived "Top Issues", and an AI-written narrative), and (3) has anyone done anything about it (Recommended Actions with per-client Acknowledged / Reviewed / Needs Review accountability chips tied to the assigned Account Director and Group Director). Churn Risk is a workflow surface, not just a report: users triage actions, write notes, create Asana tasks, and hand off AI-drafted narratives to Iris (iris.novapower.io) directly from a client row.
Access & visibility
The Churn Risk module is reachable at /predictions/churn and /predictions/churn/:clientId (per-client deep link). Both routes are wrapped in the MemberAllowedRoute guard in src/App.tsx: if the signed-in user is a base-tier "Member" (no elevated role), they are redirected to /summary. Any elevated role passes — Team Lead, Admin, Gandalf (super-admin tier), or Sauron (hardcoded super-admin list). In practice this means "Team Lead and above." There is no separate feature flag for the route itself.
Navigation: Churn Risk appears in the left sidebar under the "Client Health" section (alongside Portfolio Review, POC Management, Client Profitability, Division Forecast, and Service Expansion) and is that section's default route. The "Client Health" section has no section-level role gate of its own; base-tier Members never see it because the Member nav filter in src/App.tsx strips their sidebar down to Summary and Employees only.
How access is granted: user roles (Team Lead / Admin / Gandalf) live in Signal's own records (the app_users table managed on the General Access screen at /users, which is Gandalf-gated). Someone needing Churn Risk access should ask a Signal admin to raise their role to Team Lead or above; authentication itself is Google OAuth restricted to @powerdigitalmarketinginc.com. For login or authentication problems, contact the IT team.
Two in-module feature flags (environment variables, not per-user):
VITE_USE_SNAPSHOT_ACTIONS — when set to the string 'true', Recommended Actions come from the weekly Monday snapshot (stable all week, with history); otherwise they are regenerated client-side on every load. Code constant behavior as of Jul 2026.
VITE_SHOW_CHURN_JOURNEY — kill switch for the Iris Draft tab; the tab shows unless this is set to the string 'false' (default on).
Data sources & lineage
All Churn Risk data flows through Signal's Express backend or direct reads of Signal's own records; the browser never queries the warehouse directly. The main payload is GET /api/predictions/churn → fetchChurnData() in server/predictions.ts, cached server-side for 15 minutes (cache key predictions:churn:v2). Within that fetch, the churn score table is always fetched fresh while the client-feature, POC, and finance tables are cached up to 15 minutes (_TABLE_TTL_MS in server/predictions.ts).
On-screen element | Origin system | Code path | Refresh | Caveat |
Churn Risk / Client Profile Risk / Sentiment Risk / Performance Risk scores | AI/ML churn model (weekly pipeline run by the AI/ML team, outside the Signal repo) | GET /api/predictions/churn → fetchChurnData() (server/predictions.ts; model outputs CHURN_SCORE, RISK_SCORE_NORM, SENTIMENT_SCORE, PERFORMANCE_SCORE) | Model refreshes weekly; API response cached 15 min | Signal passes scores through — it does not recompute them |
Summary cards (Critical / High counts; Core / Growth / Enterprise high-risk counts) | Derived in the browser from the AI/ML model scores | ChurnOverviewTab.tsx summary-cards block | Same as main payload | Critical/High cards only count clients with monthly GP > 0 and not "Full Churn"; tier cards use the actionable-client rule |
Client attributes (tier, priority, division, industry, GD/AD names, contract dates, blueprints, weeks-to-end, M2M flag, churn status) | Model feature table assembled upstream by the AI/ML data pipeline (contract facts originate in nova; the churn status / forecast confidence is human-entered upstream — entry surface not defined in the app repo) | fetchChurnData() joins the feature table onto scores | 15-min table cache; upstream weekly | GD/AD names here come from the model feature table, not from Signal's team-assignment records |
MGP, Current MRR, Last Month VABO columns | Vena (Finance actuals) | fetchChurnData() reads the Vena-clients rollup (CURRENT_MONTH_MGP, CURRENT_MRR, LAST_MONTH_VABO) | 15-min table cache; upstream on Finance's posting cadence | MGP can be $0 for new contracts before Finance posts; on-screen tooltips state the Vena origin |
Revenue column (Active Contract Retainer) | nova (contract system) | fetchChurnData() reads TOTAL_ACTIVE_RETAINER from the feature table | Same as feature table | MGP (Vena) and Revenue (nova) can legitimately diverge — different systems |
Department filter values | Vena (current-month contract departments) | fetchChurnData() reads current-month DEPARTMENT_NAME rows | Current calendar month only | — |
Status column (Acknowledged / Reviewed / Needs Review / Unassigned) | Signal's own records (action feedback entered by users in Signal) | Browser reads recommended_action_feedback + app_users via Supabase REST (src/services/supabase.ts); optional POST /api/recommended-actions/latest-bulk for snapshot keys | Live | "Needs Review" only fires for priority clients: score ≥ 0.5, top 25 by score × monthly GP (code constants as of Jul 2026, ChurnOverviewTab.tsx) |
Distribution charts (risk histogram, sentiment pie, at-risk-by-tier pie) | AI/ML churn model | Server-computed overviewData in fetchChurnData() | Same as main payload | Sentiment pie counts ALL clients; tier pie counts only clients with score ≥ 0.30 (code constant) |
Churned / Contract Ended bottom table | Same as main table | Clients failing the actionable rule (isActionable in ChurnOverviewTab.tsx) | Same as main payload | Reference-only, rendered dimmed |
AI Summary tab | Anthropic Claude (model claude-sonnet-4-6 as of Jul 2026), generated server-side from the same churn payload; persisted in Signal's own records | GET /api/client-summaries/:id?type=churn; POST /api/client-summaries/:id/regenerate (auth required); prompt in server/summaryPrompt.ts; weekly persistence in server/snapshotClientSummaries.ts | Weekly cron Mondays ~09:15 server time; lazy-generated on first open mid-week | Regenerate overwrites the current week's stored row |
Brand Intel tab | Anthropic Claude (model claude-sonnet-4-5 + web search, prompt brand_intel_v2 as of Jul 2026); persisted in Signal's own records (macro_brand_insights) | Browser reads macro_brand_insights; on-demand generate via backend (server/brandIntel.ts) | Monthly cadence per client; also fed by a sibling monthly enrichment pipeline outside this repo | ~$0.46–0.50 per generation shown in UI; per-user daily cap (default 50/day, env-tunable BRAND_INTEL_DAILY_CAP_PER_USER) |
Top Issues tab | Derived in the browser from the churn payload | getKeyFlags() in ChurnClientDetail.tsx | Live with payload | Deterministic rules, no LLM |
Recommended Actions tab (auto actions) | Rule engine over the churn payload (src/views/predictions/recommendedActions.ts); optionally the weekly snapshot stored in Signal's own records (recommended_actions_snapshots) | Client-side generation, or GET /api/recommended-actions/:id + /history when VITE_USE_SNAPSHOT_ACTIONS='true' | Snapshot cron Mondays ~09:00 server time; live otherwise | Rule categories: contract urgency, financial distress, sentiment erosion, performance failure, structural risk, plus compound patterns — all code constants |
Action Done/Dismiss/Undo + history | Signal's own records (recommended_action_feedback, append-only event log) | Supabase REST direct from browser | Live | Also drives the overview Status column |
Manual follow-ups | Signal's own records (manual_recommended_actions) | src/services/manualActions.ts | Live | User-created; severity low/medium/high; archivable |
Per-action notes | Signal's own records (action_notes) | src/services/actionNotes.ts | Live | Threaded per action key |
Client notes | Signal's own records (client_notes) | src/services/clientNotes.ts | Live | Create/edit/archive in the panel |
Iris Draft tab (Journey Summary) | Composite: AI/ML model scores (live + 3-week historical archive), action snapshots and feedback from Signal's own records, prior narratives; text generated by Anthropic Claude and persisted as a churn_journey row in client_summaries | GET /api/churn-journey/:id; POST /api/client-summaries/:id/regenerate (type churn_journey); server/journeySummary.ts | On demand; persisted per week | Includes grounding-citation validation ([D:field=value] markers → advisory warnings) and a prompt-version drift banner |
Risk Score History chart | AI/ML churn model's historical weekly score archive | GET /api/predictions/churn/history/:clientId → fetchScoreHistory() (server/predictions.ts) | Weekly points (latest run per week) | Background bands at the 0.3 / 0.5 / 0.6 thresholds |
Salesforce section (open opportunities, close rates, won/lost last 3 months, failed SE attempts) | Salesforce (opportunity data joined into the model score table upstream) | Main churn payload fields (open_contracts, sf_close_rate, won/lost 3M, FAILED_SE_IN_LAST_2_WEEKS, etc.) | Freshness stamp shown in UI ("Salesforce data refreshed: …") | JSON blobs parsed server-side |
Performance Signals (Revenue Trend, Spend Efficiency, Goal Pacing, Invoice Status) | AI/ML churn model performance sub-scores (PERF_FINANCIAL_TREND, PERF_EFFICIENCY, PERF_GOAL_PACING, PERF_AR) + unpaid-invoice figures | Main churn payload | Weekly with model | AR label derived from unpaid invoice amounts |
Sentiment Signals (Budget Signal, Perf. Satisfaction, Relationship Health, Negative Mood, Pulse Sentiment, NPS) | AI/ML churn model sentiment sub-scores; upstream inputs are Gong call analysis (GONG_SCORE) and Client Pulse submissions entered in Signal's Pulse module (PULSE_SCORE); NPS origin not defined in the app repo | Main churn payload (SENT_* fields, LATEST_NPS_SCORE) | Weekly with model | Source label can read "gong", "gsheets", or "gong+gsheets" — "gsheets" is legacy naming for Pulse data, which is now entered in Signal |
POC Contacts accordion | Gong (per-contact call-derived scores: satisfaction, engagement, churn risk, decision influence, mood, call rates over last 5 weeks), assembled upstream into the POC sentiment table | Main churn payload → buildPocMap() (server/predictions.ts); rendered by PocAccordion.tsx | 15-min table cache; upstream weekly | is_decision_maker is hardcoded false pending an upstream column (code TODO as of Jul 2026) |
Asana Tasks card + Create Task | Asana (live task status via server-held token) + Signal's own records (asana_links task↔client links) | GET /api/asana/clients/:id/tasks, POST /api/asana/tasks (auth required); inbound Asana webhook keeps links current | Live (60s pull refresh fallback) | Shows a "not configured" state if the server lacks Asana credentials |
Contract & Finance / Active Contracts (Advanced Details) | nova (contract system, per-contract JSON with GP, dates, finance-approval status, services) | ACTIVE_CONTRACT_DETAILS field in the main payload | Same as feature table | — |
"Open in Nova" header link | Navigation only | — | — | |
Column show/hide configuration | Browser localStorage (per browser, key namespace churn-overview) | useTableConfig (src/components/useTableConfig.ts) | Persists locally | Not synced across devices |
Usage telemetry (invisible) | Signal's own records (signal_usage_events) | logUsageEvent on page view (module churn) and row expand (event client_detail_view) | Live | Feeds adoption reporting; app-wide freeze telemetry (perf/longtask events) also logs while on this route |
Metrics & definitions
All metrics below appear on the Churn Risk view (/predictions/churn in Signal). Threshold numbers are code constants as of Jul 2026 unless noted.
Churn Risk (composite score) — 0–1 likelihood the client churns, produced weekly by the AI/ML team's churn model outside Signal. Displayed as a bar meter and banded: Critical ≥ 0.6, High 0.5–0.6, Medium 0.3–0.5, Low < 0.3 (deriveRiskCategory in server/predictions.ts). Origin: AI/ML model.
Client Profile Risk — 0–1 sub-score for structural/profile risk (normalized RISK_SCORE_NORM from the model). Origin: AI/ML model.
Sentiment Risk — 0–1 sub-score for client sentiment (model SENTIMENT_SCORE; detail-panel bands: ≥0.8 Critical, ≥0.5 Concerning, ≥0.3 Mixed, else Positive). Upstream inputs: Gong call analysis and Client Pulse submissions. Origin: AI/ML model.
Performance Risk — 0–1 sub-score for delivery/performance risk (model PERFORMANCE_SCORE; detail-panel bands: ≥0.9 Critical, ≥0.6 Underperforming, ≥0.3 Mixed, else Healthy). Origin: AI/ML model.
MGP (Monthly Gross Profit) — current-month gross profit for the client. Origin: Vena finance actuals. Can be $0 for new contracts before Finance posts.
Current MRR — monthly recurring revenue. Origin: Vena finance actuals.
Last Month VABO — prior-month VABO value. Origin: Vena finance actuals.
Revenue (Active Contract Retainer) — total active monthly retainer from contract records. Origin: nova contract data. Expect divergence from Vena MGP — different systems.
Churn Status / Forecast Confidence — human-entered renewal forecast (values include "Confirmed Renewal", "90% confidence", "75% confidence", "40-50% confidence", "0-39% confidence", "Full Churn", "Downchurn", "Approved Pause", "M2M Continued", "Early Out Not Executed"). It arrives with the model feature data; where humans enter it is not defined in the app repo. This is independent of the model's score — disagreement between the two is a discussion signal, not a bug.
Weeks to End — weeks until contract end date. Origin: nova contract data via the model feature table.
Status chip (Acknowledged / Reviewed / Needs Review / Unassigned) — accountability state computed in the browser from Signal's own action-feedback records: Acknowledged = the assigned AD or GD has triaged (done or dismissed) every recommended action; Reviewed = someone other than the assigned owner did; Needs Review = a priority client whose actions are untouched; Unassigned = a priority client with no resolvable AD/GD. Priority client = churn score ≥ 0.5 AND in the top 25 clients by (score × monthly GP) — both code constants in ChurnOverviewTab.tsx as of Jul 2026.
At-risk (charts only) — score ≥ 0.30 (code constant RISK_SCORE_THRESHOLD in server/predictions.ts); gates the at-risk total and the at-risk-by-tier pie only.
Summary cards — Critical and High cards count clients in those score bands with monthly GP > 0 and churn status ≠ "Full Churn". Core / Growth / Enterprise cards count Critical+High clients in each business tier among actionable clients (not Full Churn; "Contract Ended" stage counts only if status is "Confirmed Renewal"). Tier assignment (Core/Growth/Enterprise) is consumed from the model feature data; the assignment rules live upstream and are not defined in the app repo.
Sentiment category (pie chart) — Client Pulse sentiment banded as Enthusiastic (4–5), Comfortable (3), Neutral (2), Concerned (1), Unknown. Origin: Client Pulse submissions entered in Signal, scored through the AI/ML pipeline.
NPS — latest NPS score shown in Sentiment Signals. The collection mechanism upstream is not defined in the app repo.
How it's used
Real workflows on the Churn Risk view (/predictions/churn) in Signal:
Monday portfolio triage (Group Director). Open Churn Risk — default sort is MGP descending with the Critical/High/Medium risk filter pre-applied, so the most valuable at-risk clients are on top. Scan the Status column for "Needs Review" chips on your accounts (top-25 dollar-weighted at-risk clients where nobody has triaged). Expand each row, read the AI Summary and Top Issues, then mark each Recommended Action Done or Dismissed. The chip flips to Acknowledged — the module's definition of "this risk has an owner and a response."
Pre-call prep (Account Director). Search the client, expand the row. Read the AI Summary for a one-paragraph account state, check Brand Intel for external context (earnings, leadership changes, talking points), open POC Contacts to see which stakeholder's call sentiment is cooling, and skim the Salesforce section for open opportunities. Optionally generate the Iris Draft and copy it into Iris (iris.novapower.io) to prepare client-facing follow-up.
Renewal-window sweep (division lead). Filter Contract Ending = within 60 days, check "Exclude M2M", sort by MGP. Compare the human Forecast Confidence column against the model's Churn Risk score — disagreements (model says Critical, human says 90% renewal) are exactly the accounts to discuss. Export the filtered set to CSV (churn-risk-clients.csv) for the meeting doc.
Turning risk into tasks. From a Recommended Action, create an Asana task pre-filled with the action text and client context; it appears in the Asana Tasks card with live status. Add a manual follow-up for anything the rule engine missed, and leave per-action notes so the next reviewer sees what was tried.
"Did our intervention work?" retrospective. Expand the client, open the Risk Score History chart to see whether the weekly score bent downward after the intervention, and check the Recommended Actions history (who did what, when). The Iris Draft narrative explicitly synthesizes the 3-week trajectory against executed actions.
Sentiment-led save play. Scan for clients with high Sentiment Risk but healthy Performance. Open Sentiment Signals to see which component drives it (Budget Signal vs. Relationship Health vs. Negative Mood), then use POC Contacts to identify the specific person whose call sentiment dropped, and plan outreach.
What users can change here
Every write from the Churn Risk view lands in Signal's own records or in Asana. Nothing on this screen writes to the churn model, Vena, nova, Salesforce, or Gong.
Recommended Action triage — Done / Dismiss / Undo buttons append events to Signal's recommended_action_feedback log. Side effect: drives the Acknowledged / Reviewed / Needs Review status chips on the overview table for everyone.
Manual follow-ups — create / edit / archive rows in Signal's manual_recommended_actions (severity low/medium/high).
Per-action notes — create / edit / archive threaded notes in Signal's action_notes, keyed to a specific recommended action.
Client notes — create / edit / archive journal entries in Signal's client_notes.
Asana task creation — creates a real task in Asana (via the server's bot token) and a link row in Signal's asana_links; the link can be archived from the card. Task status then syncs back via an Asana webhook.
AI Summary → Regenerate — re-runs the Claude generation server-side and overwrites the current week's row in Signal's client_summaries (stamped with who regenerated). Auth required.
Iris Draft → Generate/Regenerate — writes a churn_journey row to Signal's client_summaries.
Brand Intel → Generate — runs a Claude + web-search enrichment server-side (~$0.46–0.50 per run, shown in UI) and inserts into Signal's macro_brand_insights. Side effect: counts against a per-user daily cap (default 50/day as of Jul 2026, env-tunable).
Column show/hide — persisted in the user's browser localStorage only (not synced across devices).
Invisible — page views and row expansions log to Signal's signal_usage_events (module churn), which feeds adoption reporting.
Users cannot change from this screen: the churn score or any sub-score, the Churn Status / Forecast Confidence value, team assignments (GD/AD), tier, or any finance figure — all of those come from upstream systems.
Caveats & data quality
Thresholds are code constants, not policy. Risk bands (0.3 / 0.5 / 0.6), the charts' at-risk threshold (0.30), and the "priority client" rule (score ≥ 0.5, top 25 by score × monthly GP) are hardcoded in the app as of Jul 2026 and may be tuned. Treat them as "current thresholds."
Two revenue numbers by design. MGP/MRR/VABO come from Vena finance actuals; the Revenue column comes from nova contract data. They can diverge, and MGP can be $0 for new contracts before Finance posts.
Score freshness is mixed within one payload. The model score table is fetched fresh but the client-feature/finance tables are cached up to 15 minutes, and the whole API response is cached 15 minutes — small transient inconsistencies are possible and harmless at the model's weekly cadence.
Upstream model is a black box to this repo. The weekly churn model (scores, feature table, historical archive) is produced by the AI/ML team's pipeline outside the Signal codebase. Exact run day/time, model version cadence, and pipeline owner: not defined in the app repo.
Churn Status entry surface unknown. The human-entered Forecast Confidence values ride in with model feature data; where humans enter them is not defined in the app repo.
Legacy labels. The sentiment source label can display "gsheets" — legacy naming; Client Pulse submissions are now entered in Signal (Pulse module), not Google Sheets. POC contacts' is_decision_maker is hardcoded false pending an upstream column.
AI model details will drift. AI Summary uses Claude claude-sonnet-4-6 and Brand Intel uses claude-sonnet-4-5 with prompt version brand_intel_v2 as of Jul 2026; treat model IDs and per-run cost (~$0.46–0.50) as implementation details.
Snapshot flag changes behavior. With VITE_USE_SNAPSHOT_ACTIONS='true' the Recommended Actions list is frozen to the Monday snapshot with week-of labels and 4-week history; without it, actions are regenerated live per load. Whether the flag is on in production is env-driven — not answerable from the repo.
Iris Draft is an actively hardened area. The grounding-warning panel ([D:field=value] citation validation) and prompt-version drift banner are recent trust features; expect chrome changes.
Weekly crons are server-time. Recommended Actions snapshot Mondays ~09:00, Client Summaries snapshot Mondays ~09:15 (staggered 15 min apart to avoid contention). Both run a startup catch-up if the week's snapshot is missing.
NPS and tier-assignment logic (Core/Growth/Enterprise) are consumed as-is from upstream; their definitions are not in the app repo.
Gong pipeline cadence (call analysis → model inputs) is upstream of this repo and not defined in it.
Related views
Service Expansion (/predictions/se) — sibling module sharing the same backend file (server/predictions.ts), the same feature/POC data and 15-minute cache, and the same snapshot/summary/feedback infrastructure. Churn Risk's Salesforce section shows open SE opportunities and recent failed SE attempts. Note: SE's "Performance" tile uses a different, inverted rubric (high = good there) — the two values will not match by design.
Portfolio Review (/predictions/portfolio) — consumes the same churn payload; Account Director overrides entered in Signal (client_account_directors) apply there, not to the Churn Risk table's AD column (which comes from the model feature data).
POC Management (/predictions/poc-management) — built on the same Gong-derived POC sentiment data.
Division Forecast (/predictions/retention) — retention/forecast rollup in the same "Client Health" nav section.
AI Solutions (/solutions) — reports churn-risk health for a solution's target clients using this module's live and historical scores.
Client Pulse (/pulse/submit) — Pulse sentiment and goal-pacing submissions entered there are upstream inputs to the churn model's sentiment components.
Pulse Summary (/predictions/pulse-summary) — admin-only view in the "Client Pulse" nav section showing pulse sentiment/pacing across the portfolio.
External KPI API (GET /api/v1/kpis/churn-risks) — machine endpoint for churned/at-risk clients, but computed from Vena revenue data, not from the churn model scores shown on this view.
Iris (iris.novapower.io) — the Iris Draft tab is an explicit handoff; ask Iris for questions specific to client data and performance.
nova (app.novapower.io) — every client header deep-links to the account page in nova; use nova to change client or team information.
FAQ
Q: Why doesn't the revenue on Churn Risk match Vena? A: The Churn Risk table shows two different money columns. MGP, Current MRR, and Last Month VABO come from Vena finance actuals and should match Vena. The "Revenue" column is the Active Contract Retainer from nova's contract records — a different system — so it can legitimately differ from Vena. Also, MGP shows $0 for new contracts until Finance posts actuals.
Q: Who can see the Churn Risk page, and how do I get access? A: Anyone with an elevated Signal role — Team Lead, Admin, Gandalf, or Sauron. Base-tier Members are redirected to the Summary page. Access is a Signal role change (managed by Signal admins on the General Access screen), so ask a Signal admin to raise your role; for login/authentication problems, contact the IT team.
Q: Where does the churn score come from, and how often does it update? A: The 0–1 churn score and its three sub-scores (Client Profile, Sentiment, Performance) are produced by the AI/ML team's churn model, which runs weekly outside of Signal. Signal displays the scores as-is — nothing on the page recomputes or overrides them. The page itself caches data for 15 minutes, but new scores only appear when the weekly model run lands.
Q: What do Critical / High / Medium / Low mean exactly? A: They are bands on the 0–1 churn score: Critical ≥ 0.6, High 0.5–0.6, Medium 0.3–0.5, Low < 0.3 (code constants as of Jul 2026). By default the table filter shows Critical + High + Medium, so Low-risk clients are hidden on first load — use the Risk Category filter to include them.
Q: What makes the Status chip say "Needs Review", and how do I clear it? A: "Needs Review" appears on priority clients — churn score ≥ 0.5 AND in the top 25 by score × monthly GP (code constants as of Jul 2026) — whose Recommended Actions haven't been triaged. It clears when every recommended action for that client is marked Done or Dismissed: if the assigned AD/GD does it, the chip becomes "Acknowledged"; if someone else does, "Reviewed". "Unassigned" means a priority client has no resolvable AD/GD on record.
Q: The model says Critical but the Churn Status column says "90% confidence" of renewal. Which is right? A: They are intentionally independent. The churn score is the AI/ML model's weekly prediction; Churn Status / Forecast Confidence is a human-entered renewal forecast that arrives from an upstream tracking process (its entry surface is not part of the Signal app). Disagreement is a feature — those accounts are the ones worth discussing.
Q: Can I change a client's churn score, Account Director, or churn status from this page? A: No. From Churn Risk you can only write triage state (action Done/Dismiss), notes, manual follow-ups, Asana tasks, and regenerate AI text. Scores come from the AI/ML model, churn status is entered upstream, finance figures come from Vena, and team/client information changes belong in nova (app.novapower.io).
Q: Why does the sentiment source say "gsheets"? A: Legacy naming. "gsheets" means the sentiment input came from Client Pulse submissions, which historically lived in Google Sheets but are now entered in Signal's Pulse module. "gong" means Gong call analysis; "gong+gsheets" means both inputs are present. It is a label lag, not a data problem.
Q: Why did the Recommended Actions list change (or stay the same) mid-week? A: It depends on a server flag. When VITE_USE_SNAPSHOT_ACTIONS is enabled, actions are frozen to a weekly snapshot taken Mondays ~09:00 server time (with a "week of" label, "new this week" markers, and 4 weeks of history), so they stay stable all week. When the flag is off, actions are regenerated from the latest data on every page load and can shift as data changes. Whether the flag is on in a given environment is a deployment setting, not visible in the app.
Q: Is the AI Summary / Brand Intel / Iris Draft text human-written? A: No — all three are generated by Anthropic Claude on Signal's server. The AI Summary is refreshed weekly (Mondays 09:15 server time) and can be regenerated on demand; Brand Intel is generated on demand with live web search ($0.50 per run, per-user daily cap, default 50/day); the Iris Draft (Journey Summary) is generated on demand and includes grounding markers ([D:field=value]) that are validated against real data, with advisory warnings when a claim can't be matched. Treat all of it as a draft to verify, and use Iris (iris.novapower.io) for client-data questions.
Q: Does the /api/v1/kpis/churn-risks API return the same churn scores as this page? A: No. That external endpoint computes churned/at-risk clients from Vena revenue data. The Churn Risk page's scores come from the AI/ML churn model via GET /api/predictions/churn. Don't expect the two to agree.
Q: Why is the POC Contacts "decision maker" flag never set? A: It is hardcoded to false in the app as of Jul 2026, pending an upstream data column. The rest of the POC data (satisfaction, engagement, mood, call rates over the last 5 weeks) is real, derived from Gong call analysis.
