Consensus Score Computation
Compute a weighted consensus score across all stakeholders in a deal based on sentiment, influence, and alignment
Instructions
Consensus Score Computation
Calculate a single numeric consensus score (0-100) for a deal based on every mapped stakeholder's sentiment, influence level, and alignment with each other. The score predicts how likely the buying committee is to reach a collective "yes" decision.
Prerequisites
- Stakeholder map with role classifications (from
stakeholder-role-classification) - Per-stakeholder sentiment and support levels (from
stakeholder-sentiment-extraction) - Influence weights by role (configured below)
- Attio deal record with stakeholder data
Formula
Influence Weights by Role
| Role | Weight | Rationale | |------|--------|-----------| | Economic Buyer | 0.35 | Controls budget, ultimate veto power | | Champion | 0.25 | Internal advocate, drives momentum | | Influencer | 0.15 | Shapes technical/operational evaluation | | End User | 0.10 | Adoption determines long-term success | | Blocker | 0.10 | Can stall or kill the deal | | Gatekeeper | 0.05 | Controls access but rarely the decision |
Support Level Scores
| Support Level | Score | |---------------|-------| | Champion (active advocate) | 100 | | Supporter (positive, passive) | 75 | | Neutral | 50 | | Skeptic (has concerns) | 25 | | Blocker (actively resists) | 0 |
Consensus Score Calculation
For each stakeholder i:
weighted_score_i = influence_weight[role_i] * support_score[support_level_i]
raw_consensus = sum(weighted_score_i for all stakeholders)
# Penalty for unengaged stakeholders (no discovery call completed)
unengaged_penalty = (count_unengaged / count_total) * 20
# Penalty for active conflict between stakeholders
conflict_penalty = count_conflict_areas * 5 (max 15)
consensus_score = max(0, raw_consensus - unengaged_penalty - conflict_penalty)
Steps
1. Pull stakeholder data from Attio
Query all contacts linked to the deal with stakeholder attributes:
attio.list_records({
object: "people",
filter: { deal_id: "{deal_id}" },
select: ["name", "title", "stakeholder_role", "stakeholder_sentiment", "stakeholder_support_level", "engagement_level", "last_interaction_date"]
})
2. Compute the score
Apply the formula above. Use the weights table. If a stakeholder has no support_level set, treat them as unengaged and apply the penalty.
Implementation in any scripting language:
weights = {"Economic Buyer": 0.35, "Champion": 0.25, "Influencer": 0.15, "End User": 0.10, "Blocker": 0.10, "Gatekeeper": 0.05}
scores = {"Champion": 100, "Supporter": 75, "Neutral": 50, "Skeptic": 25, "Blocker": 0}
weighted_sum = 0
unengaged = 0
total = len(stakeholders)
for s in stakeholders:
if s.support_level is None:
unengaged += 1
continue
w = weights.get(s.role, 0.05)
sc = scores.get(s.support_level, 50)
weighted_sum += w * sc
unengaged_penalty = (unengaged / total) * 20 if total > 0 else 0
conflict_penalty = min(len(conflict_areas) * 5, 15)
consensus_score = max(0, weighted_sum - unengaged_penalty - conflict_penalty)
3. Classify the consensus level
| Score Range | Classification | Recommended Action | |-------------|---------------|-------------------| | 80-100 | Strong Consensus | Proceed to proposal with confidence | | 60-79 | Moderate Consensus | Address skeptic concerns before proposing | | 40-59 | Weak Consensus | Significant discovery gaps; prioritize engagement with unengaged/negative stakeholders | | 0-39 | No Consensus | Deal at risk; diagnose whether the problem is coverage (haven't talked to key people) or alignment (stakeholders disagree) |
4. Store in CRM
Write the consensus score to the deal record in Attio:
PATCH https://api.attio.com/v2/objects/deals/records/{deal_id}
{
"data": {
"values": {
"consensus_score": [{"value": {score}}],
"consensus_level": [{"option": "{classification}"}],
"consensus_computed_at": [{"value": "{iso_timestamp}"}]
}
}
}
5. Track consensus trajectory
Log each computation as a PostHog event:
posthog.capture("consensus_score_computed", {
"deal_id": "{deal_id}",
"score": consensus_score,
"level": classification,
"stakeholder_count": total,
"unengaged_count": unengaged,
"conflict_count": len(conflict_areas)
})
Over time, plot the consensus score trajectory per deal. Deals where consensus improves week-over-week have higher close rates than deals where it stalls.
Via Claude (for edge cases)
When the formula produces ambiguous results (e.g., score is 60 but the Economic Buyer is a Blocker), use Claude for nuanced assessment:
POST https://api.anthropic.com/v1/messages
Body: {
"model": "claude-sonnet-4-20250514",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Given these stakeholder sentiments for a B2B deal:\n{stakeholder_summary}\n\nThe formula-based consensus score is {score}. However, {anomaly_description}.\n\nShould the consensus level be adjusted? Return JSON: {\"adjusted_score\": N, \"adjusted_level\": \"...\", \"reasoning\": \"...\"}"}]
}
Tool Alternatives
| Tool | Method | Notes | |------|--------|-------| | Anthropic Claude | API for edge-case adjustment | Best reasoning when formula is ambiguous | | Gong | Deal intelligence score | Native multi-stakeholder engagement scoring | | Clari | Revenue intelligence | Predictive consensus from engagement patterns | | Custom Python | Scripted formula | Fastest, no API cost for standard computation |
Error Handling
- Missing Economic Buyer: If no Economic Buyer is mapped, consensus score is unreliable. Flag the deal as "Economic Buyer Unknown" and cap the maximum consensus score at 60 regardless of other stakeholders.
- Single-threaded deals: If only 1 stakeholder is mapped, consensus score is meaningless. Return score = 0 with note "Single-threaded deal — multi-stakeholder discovery required."
- Stale data: If any stakeholder's last interaction was >30 days ago, flag their sentiment as potentially stale. Weight stale stakeholders at 50% of their normal influence.