Quorentra

Quorentra CRM Building the CRM Intelligence and Scoring Layer: Building from Zero — Part 36

Series: Building Quorentra CRM from Zero — A Modular, ChatGPT-Native AI CRM

Quorentra CRM Building the CRM Intelligence and Scoring Layer: Building from Zero — Part 36
Quorentra CRM Building the CRM Intelligence and Scoring Layer: Building from Zero — Part 36

1. Introduction

Part 35 introduced the AI Agent Execution Layer.

Quorentra can now receive a business goal such as:

Investigate the ACME opportunity and determine whether we need to intervene.

An agent can then:

Gather Context
Retrieve CRM Data
Search Knowledge
Evaluate Evidence
Reason
Recommend
Propose Actions

That is a major capability.

But there is an architectural problem hiding underneath it.

Suppose ten different agents need to determine whether an opportunity is becoming inactive.

Each agent could independently retrieve:

Activities
Meetings
Emails
Tasks
Opportunity Changes

and reason about whether engagement has declined.

That works.

But it is inefficient and inconsistent.

One agent might decide:

Engagement = Healthy

while another concludes:

Engagement = Declining

from the same underlying data.

The problem becomes larger as Quorentra introduces questions such as:

Which opportunities have the strongest momentum?

Which deals are becoming stale?

Which accounts have weak stakeholder coverage?

Which opportunities are progressing unusually slowly?

Which opportunities require immediate attention?

Which salesperson has the healthiest pipeline?

These questions depend on reusable business intelligence.

Instead of asking AI agents to reconstruct the same signals repeatedly, Quorentra needs a dedicated intelligence layer.

That is what we will build in Part 36.


2. From Raw CRM Data to CRM Intelligence

A traditional CRM primarily stores facts.

For example:

Opportunity Stage
Opportunity Value
Close Date
Activities
Tasks
Meetings
Contacts
Documents

These are important.

But they do not directly answer:

Is this opportunity healthy?
Is engagement improving?
Is the opportunity becoming stale?
Is there enough stakeholder involvement?
Is the deal progressing normally?
Should someone intervene?

We need derived information.

The architecture becomes:

Raw CRM Data
Features
Signals
Scores
Intelligence
ChatGPT / Agents / Workflows

3. What Is a CRM Signal?

A signal is a derived observation about CRM state.

Examples:

No customer activity for 18 days
Three customer meetings in the last 30 days
Two overdue follow-up tasks
Proposal deadline is six days away
Opportunity has only one customer stakeholder
Customer response frequency decreased by 40%
Opportunity remained in Proposal for 35 days

These are not yet overall judgments.

They are structured observations.


4. What Is a Score?

A score combines one or more signals into a normalized business measure.

For example:

Engagement Score:
72 / 100

or:

Opportunity Health Score:
58 / 100

A score is useful because it allows:

Ranking
Filtering
Trend Analysis
Thresholds
Automation
Dashboards
Agent Reasoning

But scores must remain explainable.


5. The Most Important Rule

The core principle for Part 36 is:

A score without evidence is not intelligence.

If Quorentra says:

Opportunity Health = 42

the user should be able to ask:

Why?

And Quorentra should answer with evidence such as:

- No customer activity for 18 days.
- Two follow-up tasks are overdue.
- The proposal deadline is six days away.
- Stakeholder coverage is limited to one active contact.
- The opportunity has remained in Proposal 12 days longer than the tenant baseline.

That is much more useful than an unexplained number.


6. Deterministic Intelligence First

Part 35 introduced AI reasoning.

It might therefore be tempting to ask an LLM:

Give this opportunity a health score between 0 and 100.

That should not be our core scoring architecture.

Why?

Because the same opportunity might receive:

61

today and:

67

tomorrow without any CRM data changing.

That makes:

Trend Analysis
Automation Thresholds
Regression Testing
Auditing
Historical Comparison

much harder.

Therefore:

Core CRM scores should initially be deterministic.

AI can explain and interpret them.

It should not secretly define them.


7. Intelligence Architecture

The architecture becomes:

CRM Domain Data
Feature Extraction
Signal Calculation
Score Calculation
Intelligence Store
┌─────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼
ChatGPT Agents Workflows Analytics

This creates a reusable intelligence substrate.


8. IntelligenceSignal

Introduce:

class IntelligenceSignal(BaseModel):
signal_type: str
entity_type: str
entity_id: UUID
value: object
confidence: float | None = None
calculated_at: datetime
evidence_ids: list[str] = []

A signal represents a specific derived fact.


9. Example Signal

For example:

{
"signal_type": "days_since_customer_activity",
"entity_type": "opportunity",
"entity_id": "...",
"value": 18,
"calculated_at": "2026-08-03T08:00:00Z",
"evidence_ids": [
"activity:12345"
]
}

This signal is deterministic.

Given the same CRM state and calculation time, Quorentra should produce the same result.


10. Signal Types

Create a controlled registry of signal types.

Examples:

days_since_customer_activity
customer_activity_count_7d
customer_activity_count_30d
meeting_count_30d
email_count_30d
open_task_count
overdue_task_count
days_in_current_stage
days_until_close
stakeholder_count
active_stakeholder_count
decision_maker_identified
proposal_document_present
proposal_deadline_days
customer_response_latency
activity_momentum
stage_velocity
engagement_trend

Do not use arbitrary string signals throughout the codebase without central definitions.


11. SignalDefinition

Introduce:

class SignalDefinition(BaseModel):
key: str
name: str
description: str
entity_type: str
value_type: str
unit: str | None = None

Example:

Key:
days_since_customer_activity
Name:
Days Since Customer Activity
Entity:
Opportunity
Value Type:
integer
Unit:
days

12. Signal Evidence

Every meaningful signal should point back to its source.

For example:

Signal:
days_since_customer_activity = 18

Evidence:

Last customer activity:
2026-07-16
Calculation time:
2026-08-03

This creates traceability.


13. SignalEvidence

Introduce:

class SignalEvidence(BaseModel):
source_type: str
source_id: UUID
field: str | None = None
observed_value: object | None = None

A signal may have multiple evidence items.


14. Evidence Is More Than Citations

Evidence allows Quorentra to answer:

Where did this signal come from?
Which record caused it?
Which timestamp was used?
Which meeting contributed?
Which task was overdue?

This becomes essential for user trust and debugging.


15. Features Versus Signals

It is useful to distinguish features from business signals.

A feature is usually a lower-level calculated value.

For example:

activity_count_30d = 8

A signal may interpret that feature:

recent_activity_level = moderate

And a score may combine several signals:

engagement_score = 71

The hierarchy becomes:

CRM Data
Features
Signals
Scores

16. FeatureDefinition

Introduce:

class FeatureDefinition(BaseModel):
key: str
entity_type: str
value_type: str
description: str
calculation_version: str

Examples:

customer_activity_count_7d
customer_activity_count_30d
customer_activity_count_90d
meeting_count_30d
days_since_last_activity
days_in_stage
open_task_count
overdue_task_count

17. FeatureValue

Persist reusable feature values:

class FeatureValue(Base):
__tablename__ = "feature_values"
id: Mapped[UUID]
organization_id: Mapped[UUID]
entity_type: Mapped[str]
entity_id: Mapped[UUID]
feature_key: Mapped[str]
value_json: Mapped[dict]
calculation_version: Mapped[str]
calculated_at: Mapped[datetime]

Tenant isolation remains mandatory.


18. Why Persist Features?

We could calculate everything on demand.

But persistence gives us:

Faster Reads
Historical Analysis
Trend Detection
Agent Efficiency
Dashboard Performance
Reproducibility

It also reduces repeated calculations across ChatGPT, workflows, agents, and frontend dashboards.


19. Feature Store

We can introduce a lightweight feature store abstraction.

Do not interpret this as requiring a dedicated machine-learning feature platform.

For the MVP:

PostgreSQL

is sufficient.

The logical abstraction is more important than the infrastructure.


20. FeatureStore

Introduce:

class FeatureStore:
async def get_feature(
self,
*,
organization_id: UUID,
entity_type: str,
entity_id: UUID,
feature_key: str,
):
...
async def save_feature(...):
...

This gives the intelligence layer a consistent interface.


21. Signal Freshness

Signals become stale.

For example:

days_since_customer_activity = 18

will be wrong tomorrow even if no CRM event occurs.

Therefore every signal needs freshness semantics.


22. SignalFreshness

Define concepts such as:

calculated_at
valid_until
freshness_status

Possible statuses:

fresh
stale
expired

A user should not receive an old score as if it were current.


23. Event-Driven Recalculation

Many signals can update when CRM events occur.

For example:

activity.created
Recalculate Engagement Features

or:

opportunity.stage_changed
Recalculate Stage Features

The Part 34 event architecture becomes useful again.


24. Scheduled Recalculation

Some features depend on the passage of time.

Examples:

days_since_last_activity
days_in_stage
days_until_close
task_overdue_days

These require scheduled recalculation.

Architecture:

Schedule
Workflow / Intelligence Job
Find Relevant Entities
Recalculate Time-Based Features

25. Hybrid Recalculation

The best approach is usually:

Event Driven
+
Scheduled

Events provide fast updates.

Schedules ensure time-based features remain accurate.


26. FeatureCalculator

Introduce:

class FeatureCalculator:
async def calculate(
self,
*,
organization_id: UUID,
entity_type: str,
entity_id: UUID,
feature_key: str,
as_of: datetime,
):
...

Each feature calculation should be deterministic and versioned.


27. Calculation Versioning

Suppose we initially define:

activity_count_30d

as all activities.

Later we decide internal notes should not count as customer engagement.

The meaning has changed.

Therefore calculations need versions.

For example:

activity_count_30d:v1
activity_count_30d:v2

Historical values should retain the version that produced them.


28. SignalCalculator

Introduce:

class SignalCalculator:
async def calculate(
self,
*,
entity_id: UUID,
signal_type: str,
as_of: datetime,
) -> IntelligenceSignal:
...

The calculator consumes features and CRM evidence.


29. Engagement Signals

One of the first intelligence families should be engagement.

Possible features:

customer_activity_count_7d
customer_activity_count_30d
meeting_count_30d
email_count_30d
days_since_customer_activity
average_response_latency

Derived signals:

engagement_level
engagement_trend
engagement_decline
engagement_consistency

30. Engagement Score

Normalize engagement into:

0–100

where:

0
=
No meaningful engagement

and:

100
=
Very strong recent engagement

Do not interpret 100 as a guarantee that the opportunity will close.

It only represents the defined engagement dimension.


31. Example Engagement Components

An MVP formula might include:

Recency of Customer Activity 30%
Customer Activity Frequency 25%
Meeting Frequency 20%
Customer Response Behavior 15%
Engagement Trend 10%

These weights are explicit.

They are not hidden inside an LLM prompt.


32. Score Component

Introduce:

class ScoreComponent(BaseModel):
key: str
weight: float
raw_value: float
normalized_value: float
contribution: float

This makes every score decomposable.


33. Score Calculation

Conceptually:

Score
=
Σ(normalized_component × weight)

For example:

Recency 80 × 0.30 = 24.0
Frequency 70 × 0.25 = 17.5
Meetings 60 × 0.20 = 12.0
Response 50 × 0.15 = 7.5
Trend 40 × 0.10 = 4.0
---------------------------------
Engagement Score = 65

Now the score can be explained precisely.


34. ScoreDefinition

Introduce:

class ScoreDefinition(BaseModel):
key: str
name: str
description: str
entity_type: str
minimum: float
maximum: float
version: str
components: list[ScoreComponentDefinition]

Definitions should be immutable once used historically.


35. ScoreValue

Persist:

class ScoreValue(Base):
__tablename__ = "score_values"
id: Mapped[UUID]
organization_id: Mapped[UUID]
entity_type: Mapped[str]
entity_id: Mapped[UUID]
score_key: Mapped[str]
score_version: Mapped[str]
value: Mapped[float]
calculated_at: Mapped[datetime]
explanation_json: Mapped[dict]

36. Historical Scores

Do not overwrite every previous score.

Suppose:

July 1:
Engagement = 84
July 15:
Engagement = 76
August 1:
Engagement = 59

The trend itself contains valuable intelligence.

If we retain only:

59

we lose that information.


37. Score History

The intelligence store should therefore support:

Current Score
Historical Scores
Score Trend

This enables questions such as:

Which opportunities experienced the largest engagement decline during the last 30 days?


38. Opportunity Health Score

Now we can build a higher-level score.

Potential components:

Engagement
Activity Momentum
Stage Progress
Task Execution
Stakeholder Coverage
Close-Date Risk
Deal Velocity
Known Risk Signals

This produces:

Opportunity Health Score

39. Health Is Multi-Dimensional

Do not reduce everything to one opaque score.

For example:

Opportunity Health:
58

should also expose:

Engagement:
42
Momentum:
51
Stakeholder Coverage:
80
Task Execution:
65
Deal Velocity:
44

The aggregate score provides ranking.

The dimensions provide understanding.


40. Opportunity Health Example

For ACME:

Engagement 42
Activity Momentum 48
Stakeholder Coverage 75
Task Execution 61
Deal Velocity 44
Close-Date Readiness 35

Weighted result:

Opportunity Health = 49

That tells us more than the number 49 alone.


41. Score Bands

Numbers are useful for machines.

Humans often benefit from bands.

For example:

80–100
Healthy
60–79
Watch
40–59
At Risk
0–39
Critical

These thresholds should also be versioned configuration.


42. Avoid False Precision

A score of:

61.384729

suggests a degree of accuracy that probably does not exist.

For CRM users, expose:

61

or:

61 / 100

Internally, calculations may retain greater precision.


43. Staleness Score

A staleness score estimates how inactive an opportunity has become.

Possible components:

Days Since Customer Activity
Days Since Opportunity Update
Days Since Meeting
Days Since Task Completion
Days in Current Stage

Higher values could indicate greater staleness.


44. Activity Momentum

Momentum asks:

Is activity increasing or decreasing?

Compare windows such as:

Last 14 Days

versus:

Previous 14 Days

Example:

Previous period:
12 customer activities
Current period:
5 customer activities

This produces:

Activity Momentum:
Declining

45. Momentum Calculation

A simple deterministic formula might be:

(current_period - previous_period)
/
max(previous_period, 1)

For example:

(5 - 12) / 12
=
-0.583

or approximately:

-58%

This becomes a strong negative engagement signal.


46. Deal Velocity

Deal velocity measures how quickly an opportunity progresses.

Useful features include:

Days in Current Stage
Average Days per Stage
Stage Transition Frequency
Days Since Last Stage Change
Total Opportunity Age

But velocity should be compared with context.

A €20,000 deal and a €5 million enterprise transformation opportunity naturally progress differently.


47. Tenant Baselines

This introduces an important concept:

Tenant Baseline

For example:

Average Proposal Stage Duration:
Tenant = 23 days
ACME = 37 days

Therefore:

ACME is 14 days slower than tenant baseline.

That is more informative than simply saying:

ACME has been in Proposal for 37 days.

48. BaselineDefinition

Introduce:

class BaselineDefinition(BaseModel):
key: str
entity_type: str
metric: str
segment_dimensions: list[str]

Potential segmentation:

Opportunity Value Band
Pipeline
Region
Product
Industry

But keep MVP segmentation limited.


49. Minimum Sample Size

Do not calculate misleading baselines from tiny datasets.

For example:

Average proposal duration based on 2 opportunities.

That may not be meaningful.

Introduce:

BASELINE_MIN_SAMPLE_SIZE

If insufficient data exists, mark:

baseline_unavailable

instead of pretending statistical confidence.


50. Stakeholder Coverage

CRM opportunities often fail because engagement is concentrated in one person.

Useful features:

total_stakeholders
active_stakeholders
decision_maker_present
executive_sponsor_present
technical_contact_present
business_contact_present

A simple stakeholder coverage signal can indicate:

strong
moderate
weak

51. Stakeholder Risk Example

Suppose ACME has:

Contacts:
5
Active Opportunity Stakeholders:
1
Decision Maker:
Unknown

Quorentra can derive:

Stakeholder Coverage:
Weak

with evidence pointing to the associated contacts and opportunity relationships.


52. Task Execution Signals

Tasks provide operational signals.

Examples:

open_task_count
overdue_task_count
high_priority_overdue_count
task_completion_rate_30d
average_task_delay
follow_up_task_coverage

These can contribute to opportunity health.


53. Meeting Signals

Meeting-derived features:

meeting_count_30d
days_since_last_meeting
meeting_frequency
customer_participant_count
internal_participant_count
meeting_commitment_count

Later, Quorentra can add more sophisticated meeting intelligence.

For the MVP, keep core calculations deterministic.


54. Communication Signals

If communication data is available:

email_count_30d
customer_reply_count_30d
average_customer_reply_time
unanswered_outbound_count
days_since_customer_reply

These can significantly improve engagement intelligence.


55. Positive Buying Signals

Some signals indicate positive momentum.

Examples:

New stakeholder added
Decision maker engaged
Proposal requested
Technical workshop scheduled
Security review started
Procurement contact introduced
Contract document requested

Initially, only use positive signals that can be derived reliably from structured CRM events.


56. Negative Risk Signals

Examples:

Engagement decline
No recent customer activity
Repeatedly postponed meetings
Overdue customer commitment
Overdue internal follow-up
Close date repeatedly moved
Opportunity stuck in stage
Decision maker absent
Proposal revision unresolved

Again, distinguish deterministic signals from AI-inferred signals.


57. Deterministic Versus AI-Derived Signals

Eventually we may support:

Signal Source:
deterministic

and:

Signal Source:
ai_inferred

For example:

days_since_customer_activity

is deterministic.

But:

customer_sentiment_declining

may require AI interpretation of meeting transcripts and communications.

These should never be presented as equivalent types of evidence.


58. SignalSource

Define:

deterministic
ai_inferred
user_entered
external

Every signal should declare its source class.

This is critical for explainability.


59. AI-Inferred Signal Confidence

AI-derived signals should include:

confidence
model_version
evidence
generated_at

For example:

Signal:
customer_concern_about_timeline
Source:
ai_inferred
Confidence:
0.86
Evidence:
Meeting transcript lines...

This gives agents useful intelligence without disguising inference as fact.


60. Do Not Let AI Overwrite Facts

Suppose CRM says:

Opportunity Stage:
Proposal

An AI model should not change the stored fact to:

Negotiation

because a meeting transcript “sounds like negotiation.”

Instead create:

Signal:
possible_negotiation_activity

The distinction between:

CRM Fact

and:

AI Inference

must remain explicit.


61. Intelligence Registry

Introduce a registry for:

Features
Signals
Scores
Baselines

For example:

class IntelligenceRegistry:
def get_feature_definition(...):
...
def get_signal_definition(...):
...
def get_score_definition(...):
...

This prevents intelligence logic from becoming scattered across the application.


62. ScoreCalculator

Introduce:

class ScoreCalculator:
async def calculate(
self,
*,
organization_id: UUID,
entity_type: str,
entity_id: UUID,
score_key: str,
as_of: datetime,
) -> ScoreValue:
...

The calculator loads required features and signals and applies the versioned definition.


63. IntelligenceService

Introduce:

class IntelligenceService:
async def recalculate_entity(...):
...
async def get_signals(...):
...
async def get_scores(...):
...
async def get_score_history(...):
...
async def explain_score(...):
...

This becomes the primary application service for derived CRM intelligence.


64. Score Explanation

A score should have a machine-readable explanation.

For example:

{
"score": 49,
"band": "at_risk",
"components": [
{
"name": "engagement",
"score": 42,
"weight": 0.30,
"contribution": 12.6
},
{
"name": "stakeholder_coverage",
"score": 75,
"weight": 0.15,
"contribution": 11.25
}
]
}

ChatGPT can then explain it naturally.


65. ChatGPT Should Explain, Not Recalculate

If the user asks:

Why is ACME at risk?

ChatGPT should retrieve:

Opportunity Health Score
Score Components
Signals
Evidence

and explain them.

It should not independently invent a second health score.


66. ChatGPT Intelligence Tools

The Apps SDK layer can expose business-level tools such as:

get_opportunity_health
get_opportunity_signals
get_engagement_score
get_score_history
explain_opportunity_score
list_at_risk_opportunities
list_declining_opportunities

These are much more useful than requiring ChatGPT to reconstruct analytics from raw records every time.


67. Example ChatGPT Interaction

User:

Why is ACME considered at risk?

ChatGPT calls:

get_opportunity_health

Quorentra returns:

Health:
49 / 100
Band:
At Risk
Engagement:
42
Momentum:
48
Stakeholder Coverage:
75
Task Execution:
61
Deal Velocity:
44
Close-Date Readiness:
35

with evidence.


68. Natural-Language Explanation

ChatGPT can then say:

ACME is currently rated 49/100, placing it in the At Risk band. The strongest negative factors are low recent engagement, declining activity momentum, slow progress through the Proposal stage, and the approaching proposal deadline. Stakeholder coverage remains comparatively healthy, so the primary issue is not account access but lack of recent progress.

That is where ChatGPT adds value.

The score itself remains deterministic.


69. Agent Access to Intelligence

Part 35 agents can now use:

get_opportunity_health
get_opportunity_signals
get_score_history

instead of reconstructing everything from scratch.

An agent may begin:

Goal:
Investigate ACME risk.

Then retrieve:

Health Score:
49
Engagement:
42
Momentum:
48

and drill into the evidence only where needed.


70. Intelligence Makes Agents More Efficient

Without Part 36:

Agent
Retrieve 50 Activities
Retrieve 10 Meetings
Retrieve 20 Tasks
Reason

With Part 36:

Agent
Retrieve Health Intelligence
Identify Weak Dimension
Retrieve Supporting Evidence
Reason

This reduces:

Tool Calls
Tokens
Latency
Cost

while improving consistency.


71. Workflows Can Use Scores

Part 34 workflows can now use intelligence.

For example:

WHEN
Opportunity Health Score Changes
IF
Health Score < 40
THEN
Create Review Task

or:

Every Morning
Find Opportunities
WHERE
Engagement Score < 50
AND
Value > €100,000

This creates powerful deterministic automation.


72. Score Change Events

Publish events such as:

intelligence.score_changed
opportunity.health_changed
opportunity.engagement_changed

But avoid publishing meaningless tiny changes.

For example:

Health:
62 → 61

may not matter.


73. Significant Change Thresholds

Introduce:

SCORE_CHANGE_EVENT_THRESHOLD

For example:

5 points

Or publish when a score crosses a band:

Watch
At Risk

Band changes are often more meaningful than small numerical movements.


74. Intelligence Event Example

{
"event_type": "opportunity.health_band_changed",
"entity_id": "...",
"payload": {
"previous_score": 63,
"new_score": 57,
"previous_band": "watch",
"new_band": "at_risk"
}
}

Part 34 workflows can consume this event.


75. Intelligence Feedback Loop

We now have:

CRM Event
Feature Recalculation
Signal Recalculation
Score Recalculation
Score Change Event
Workflow
Agent
Recommendation / Action

This is a major architectural milestone.


76. Prevent Intelligence Loops

Suppose an agent creates a task.

That causes:

task.created

which recalculates opportunity health.

That may trigger another workflow.

The correlation and causation mechanisms from Part 34 must continue to apply.

Intelligence does not bypass loop protection.


77. Historical Intelligence

Store historical score snapshots.

This enables:

Trend Charts
Before/After Analysis
Pipeline Movement
Account Deterioration
Recovery Detection
Agent Evaluation

Historical intelligence is often more useful than a current score alone.


78. ScoreTrend

Introduce:

class ScoreTrend(BaseModel):
current_value: float
previous_value: float
absolute_change: float
percentage_change: float | None
direction: str
period: str

Directions:

improving
stable
declining

79. Trend Thresholds

Do not label:

70 → 69

as meaningful decline.

Use thresholds.

For example:

absolute change < 3
=
stable

These thresholds should be part of versioned score configuration.


80. Intelligence Snapshots

For reporting, we may also create periodic snapshots.

For example:

Daily
Weekly
Monthly

A daily snapshot allows questions such as:

Show me how opportunity health changed over the last 90 days.


81. Pipeline Intelligence

Once opportunity scores exist, Quorentra can derive pipeline-level metrics.

Examples:

Average Opportunity Health
Weighted Pipeline Health
At-Risk Pipeline Value
Critical Pipeline Value
Healthy Pipeline Value
Declining Opportunity Count
Improving Opportunity Count

82. Weighted Pipeline Health

A simple metric could weight health by opportunity value.

Conceptually:

Σ(opportunity_value × health_score)
/
Σ(opportunity_value)

This prevents a €5,000 opportunity and a €5 million opportunity from contributing equally to pipeline health.


83. Do Not Confuse Health With Forecast Probability

Opportunity health and win probability are different concepts.

An opportunity can be:

Healthy

but still early-stage.

Likewise, a late-stage deal may have:

High Win Probability

while showing deteriorating engagement.

Keep separate dimensions:

Health
Probability
Value
Stage
Forecast

84. Data Quality Signals

The intelligence layer should also detect missing CRM information.

Examples:

missing_close_date
missing_opportunity_value
missing_primary_contact
missing_owner
missing_next_step
missing_decision_maker

These are valuable signals themselves.


85. Data Quality Score

Eventually we can calculate:

Opportunity Data Quality Score

This helps distinguish:

Low Health

from:

Insufficient Data

An opportunity should not receive a confident risk classification if critical information is missing.


86. Insufficient Data

Scores should support states such as:

available
partial
insufficient_data

Do not force every entity into a 0–100 score.

Sometimes the correct result is:

There is not enough information to calculate a reliable engagement score.


87. ScoreQuality

Introduce:

class ScoreQuality(BaseModel):
status: str
completeness: float
missing_features: list[str]
warnings: list[str]

This allows ChatGPT and agents to understand the limitations of the score.


88. Confidence Versus Completeness

For deterministic scores, the term:

confidence

may not always be appropriate.

Instead, use:

completeness

or:

data_quality

For AI-inferred signals, confidence remains relevant.

Keep these concepts separate.


89. Tenant-Specific Score Configuration

Eventually tenants may want different definitions.

For example:

Company A:
No activity for 14 days = risk

while:

Company B:
No activity for 30 days = normal

The architecture should eventually support tenant configuration.

But the MVP should begin with system defaults.


90. Configuration Hierarchy

Later:

System Default
Tenant Override
Pipeline Override

Avoid introducing all levels immediately.

Start with:

System Default

plus limited tenant thresholds if required.


91. Version Tenant Overrides

If a tenant changes:

Engagement Risk Threshold:
14 days → 21 days

future scores may change.

Historical calculations should remain associated with the configuration version used at that time.


92. Intelligence Module Structure

Create:

backend/app/intelligence/

Suggested structure:

backend/app/intelligence/
├── models.py
├── schemas.py
├── registry.py
├── features.py
├── feature_store.py
├── signals.py
├── scores.py
├── baselines.py
├── trends.py
├── freshness.py
├── recalculation.py
├── events.py
├── explanations.py
├── metrics.py
├── service.py
└── exceptions.py

93. Opportunity Intelligence Submodule

As complexity grows, we can introduce:

backend/app/intelligence/opportunities/

with:

engagement.py
momentum.py
velocity.py
staleness.py
stakeholders.py
tasks.py
meetings.py
health.py

But do not fragment the module prematurely.


94. Background Intelligence Worker

Feature and score recalculation can run asynchronously.

Architecture:

CRM Mutation
Domain Event
Outbox
Event Worker
Intelligence Recalculation Job
Feature Store
Signal Store
Score Store

The user-facing CRM mutation does not need to wait for every derived score to finish.


95. Eventual Consistency

This means intelligence may be:

slightly behind CRM state

for a short period.

That is acceptable if clearly designed.

Store:

calculated_at

and expose it when relevant.


96. Freshness SLA

Define expectations such as:

Event-driven scores:
updated within 60 seconds
Time-based scores:
updated daily

The exact values can evolve.

The important point is to make freshness measurable.


97. Recalculation Idempotency

The same event may be processed more than once.

Recalculation must therefore be idempotent.

For example:

entity_id
feature_key
calculation_version
as_of_bucket

can help define unique calculations.


98. Recalculation Fan-Out

One event may affect several features.

Example:

activity.created

may affect:

days_since_customer_activity
activity_count_7d
activity_count_30d
activity_momentum
engagement_score
opportunity_health_score

We need dependency tracking.


99. Intelligence Dependency Graph

Conceptually:

activity.created
activity_count_7d
activity_count_30d
days_since_activity
engagement_signals
engagement_score
opportunity_health_score

The system should understand which derived values need recalculation.


100. DependencyRegistry

Introduce:

class DependencyRegistry:
def affected_features(
self,
event_type: str,
) -> list[str]:
...
def dependent_scores(
self,
feature_key: str,
) -> list[str]:
...

This prevents recalculating every score after every event.


101. Intelligence Query API

Potential endpoints:

GET /api/v1/opportunities/{id}/intelligence
GET /api/v1/opportunities/{id}/signals
GET /api/v1/opportunities/{id}/scores
GET /api/v1/opportunities/{id}/scores/history
GET /api/v1/opportunities/{id}/health
GET /api/v1/opportunities/{id}/engagement
GET /api/v1/pipeline/intelligence

102. Internal Tool APIs

For ChatGPT and agents, prefer business-level tools:

get_opportunity_health
get_opportunity_engagement
get_opportunity_risk_signals
get_opportunity_score_history
list_at_risk_opportunities
list_declining_opportunities
get_pipeline_health

This keeps the Apps SDK surface understandable.


103. Example Intelligence Response

{
"opportunity_id": "...",
"health": {
"score": 49,
"band": "at_risk",
"calculated_at": "2026-08-03T08:00:00Z"
},
"dimensions": {
"engagement": 42,
"momentum": 48,
"stakeholder_coverage": 75,
"task_execution": 61,
"deal_velocity": 44,
"close_date_readiness": 35
},
"top_negative_signals": [
"no_customer_activity_18_days",
"proposal_revision_outstanding",
"proposal_deadline_6_days"
]
}

This is highly useful to both ChatGPT and agents.


104. Explainability Endpoint

Provide something like:

GET /api/v1/opportunities/{id}/health/explanation

It should return:

Score
Band
Components
Weights
Signals
Evidence
Calculation Version
Calculation Time
Data Quality

105. ChatGPT-Native Explanation

The user should never need to inspect score JSON.

They can ask:

Why did ACME’s health score drop this week?

ChatGPT retrieves the score history and component changes.

It may answer:

ACME dropped from 63 to 49 this week. The main change was engagement: no customer interaction has been recorded for 18 days, activity momentum fell sharply compared with the previous two-week period, and the proposal revision requested by the customer is still outstanding. Stakeholder coverage remained stable, so the decline is primarily related to engagement and deal progress.

That is exactly the kind of interaction a ChatGPT-native CRM should support.


106. Score Comparison

Users may also ask:

Compare ACME and Contoso.

Quorentra can return:

                    ACME     Contoso

Health               49        78

Engagement           42        81

Momentum             48        74

Stakeholders         75        69

Task Execution       61        82

Deal Velocity        44        77

ChatGPT can explain the differences.


107. Intelligence Ranking

Users can ask:

Which five opportunities need the most attention?

Quorentra should not send the entire opportunity database to ChatGPT.

Instead:

Intelligence Query
Rank Opportunities
Top 5
ChatGPT

This is faster, cheaper, and safer.


108. Intelligence and RAG

The intelligence layer complements RAG.

RAG answers:

What does our CRM knowledge say?

Intelligence answers:

What structured business signals can we derive?

Agents can use both:

Structured Intelligence
+
Retrieved Knowledge
Grounded Reasoning

This combination is much stronger than either alone.


109. Example Agent Flow After Part 36

Opportunity Risk Agent:

Goal
Get Opportunity Health
Health = 49
Get Weak Dimensions
Engagement = 42
Velocity = 44
Get Supporting Signals
Retrieve Evidence
Reason
Recommend

The agent becomes more efficient and more consistent.


110. Intelligence and Workflow Automation

A workflow can now be:

WHEN
health_band changes to critical
THEN
run Opportunity Risk Agent

The architecture becomes:

CRM Change
Intelligence Recalculation
Health Band Changes
Domain Event
Workflow
Agent
Recommendation

This is the beginning of proactive CRM intelligence.


111. Metrics

Add:

intelligence_feature_calculations_total
intelligence_signal_calculations_total
intelligence_score_calculations_total
intelligence_recalculation_failures_total
intelligence_stale_values_total

112. Score Metrics

Add:

opportunity_health_score_average
opportunity_engagement_score_average
opportunities_at_risk_total
opportunities_critical_total
opportunities_declining_total
opportunities_improving_total

Be careful with metric cardinality.

Do not create a Prometheus metric label for every opportunity ID.


113. Processing Metrics

Track:

intelligence_recalculation_duration_seconds
intelligence_recalculation_queue_depth
intelligence_event_to_score_latency_seconds

These help enforce freshness targets.


114. Data Quality Metrics

Track:

intelligence_insufficient_data_total
opportunities_missing_close_date_total
opportunities_missing_value_total
opportunities_missing_primary_contact_total
opportunities_missing_next_step_total

This can also reveal CRM adoption problems.


115. Testing Strategy

Part 36 requires tests for:

Feature Calculation
Signal Calculation
Score Calculation
Score Weighting
Score Bands
Historical Scores
Trends
Freshness
Recalculation
Versioning
Tenant Isolation
Baselines
Minimum Sample Sizes
Data Quality
Evidence
Workflow Integration
Agent Integration
ChatGPT Tools

116. Determinism Test

Given identical:

CRM State
Calculation Time
Calculation Version

expected:

Identical Feature Values
Identical Signals
Identical Scores

This is one of the most important tests.


117. Tenant Isolation Test

Create:

Tenant A Opportunity
Tenant B Activities

Calculate Tenant A engagement.

Expected:

Tenant B activities contribute exactly 0.

118. Evidence Test

Calculate:

days_since_customer_activity

Expected:

signal contains evidence reference to actual last customer activity

119. Historical Score Test

Calculate:

Health = 72

Change CRM data.

Recalculate:

Health = 58

Expected:

Current = 58
History contains 72 and 58

120. Version Test

Calculate using:

health:v1

Deploy:

health:v2

Expected:

Historical v1 values remain identifiable.
New values use v2.

121. Missing Data Test

Remove critical opportunity fields.

Expected:

Score Quality:
partial

or:

insufficient_data

rather than a falsely confident score.


122. Baseline Sample Test

Only two comparable opportunities exist.

Expected:

baseline_unavailable

if minimum sample size is not met.


123. Event Recalculation Test

Create a new customer activity.

Expected:

activity.created
engagement features recalculated
engagement score recalculated
health recalculated if necessary

124. Significant Change Event Test

Health changes:

61 → 60

Expected:

No health-band event

Health changes:

61 → 58

crossing:

Watch → At Risk

Expected:

opportunity.health_band_changed

125. Agent Integration Test

Risk Agent requests opportunity health.

Expected:

structured intelligence returned
evidence available
no cross-tenant information
score version included

126. ChatGPT Explanation Test

User asks:

Why is this opportunity at risk?

Expected response is based on:

Stored Score
Components
Signals
Evidence

not a newly invented score.


127. Security Considerations

The intelligence layer must enforce:

Tenant Isolation
Authorization
Evidence Scope
Safe Aggregation
Controlled Configuration
Immutable Historical Versions

Aggregated intelligence can still leak information if tenant boundaries are not applied correctly.


128. Intelligence Is Not Authorization

Suppose:

Health Score = 15

That does not automatically authorize:

Delete Opportunity
Change Owner
Send Email
Create Task

Scores can trigger workflows.

Actions still pass through the existing authorization and action architecture.


129. AI Signals Are Untrusted Inputs

If an AI-derived signal says:

customer likely to churn

treat it as intelligence evidence.

Do not treat it as authority.

It may inform:

Agent Reasoning
Workflow Conditions
Recommendations

but sensitive actions should remain governed by policy.


130. Updated Quorentra Architecture

After Part 36:

Quorentra
├── CRM Core
│ ├── Companies
│ ├── Contacts
│ ├── Opportunities
│ ├── Activities
│ ├── Tasks
│ ├── Meetings
│ └── Documents
├── Knowledge Layer
│ ├── Extraction
│ ├── Chunking
│ ├── Embeddings
│ ├── Retrieval
│ └── Grounding
├── Intelligence Layer
│ ├── Features
│ ├── Feature Store
│ ├── Signals
│ ├── Evidence
│ ├── Scores
│ ├── Baselines
│ ├── Trends
│ ├── Data Quality
│ ├── Freshness
│ └── Recalculation
├── Action Layer
│ ├── ActionIntent
│ ├── Validation
│ ├── Authorization
│ ├── Confirmation
│ ├── Idempotency
│ └── Audit
├── Workflow Layer
│ ├── Triggers
│ ├── Conditions
│ ├── Actions
│ ├── Scheduler
│ └── Execution
├── Agent Layer
│ ├── Goals
│ ├── Context
│ ├── Planning
│ ├── Tools
│ ├── Policies
│ ├── Budgets
│ ├── Approvals
│ └── Execution
└── ChatGPT Layer
├── Apps SDK
├── CRM Tools
├── Knowledge Tools
├── Intelligence Tools
├── Workflow Tools
└── Agent Tools

The intelligence layer now sits between raw CRM state and higher-level reasoning.


131. The New Information Flow

The architecture can now support:

                    CRM DATA
                       │
                       ▼
                    FEATURES
                       │
                       ▼
                    SIGNALS
                       │
                       ▼
                     SCORES
                       │
             ┌─────────┼─────────┐
             │         │         │
             ▼         ▼         ▼
          ChatGPT    Agents   Workflows
             │         │         │
             └─────────┼─────────┘
                       ▼
                 ACTION LAYER
                       │
                       ▼
                    CRM DATA

This creates a closed intelligence loop.


132. Why This Matters for a ChatGPT-Native CRM

Without an intelligence layer, ChatGPT repeatedly needs to interpret raw CRM records.

With Part 36, a user can ask:

How is my pipeline looking?

Quorentra can provide:

Pipeline Health
At-Risk Value
Critical Opportunities
Engagement Trends
Momentum Trends
Data Quality

ChatGPT can then turn those structured results into a useful executive explanation.


133. The Division of Responsibility

The architecture now becomes even clearer.

Quorentra calculates:

Facts
Features
Signals
Scores
Baselines
Trends
Evidence

ChatGPT interprets:

What It Means
Why It Matters
What the User Should Investigate
Which Questions to Ask Next
How to Explain It Naturally

Agents pursue goals:

Investigate
Gather Evidence
Compare
Reason
Recommend
Propose Actions

Workflows automate:

When
If
Then

Action services execute:

Authorized CRM Mutations

Each layer has a clear responsibility.


134. MVP Intelligence Scope

Do not attempt to build every possible CRM score immediately.

For the MVP, implement:

1. Engagement Score
2. Activity Momentum
3. Staleness Score
4. Stakeholder Coverage Score
5. Task Execution Score
6. Deal Velocity Score
7. Opportunity Health Score
8. Data Quality Score

That is already enough to make Quorentra substantially more intelligent.


135. MVP Feature Set

Start with features such as:

days_since_customer_activity
customer_activity_count_7d
customer_activity_count_30d
customer_activity_count_previous_30d
meeting_count_30d
days_since_last_meeting
open_task_count
overdue_task_count
task_completion_rate_30d
days_in_current_stage
days_until_close
stakeholder_count
active_stakeholder_count
decision_maker_present
opportunity_age_days

These provide a strong foundation.


136. MVP Score Dependencies

For example:

Engagement Score
├── days_since_customer_activity
├── customer_activity_count_30d
├── meeting_count_30d
└── activity_momentum
Task Execution Score
├── overdue_task_count
└── task_completion_rate_30d
Opportunity Health
├── Engagement
├── Momentum
├── Task Execution
├── Stakeholder Coverage
├── Deal Velocity
└── Close-Date Readiness

Keep dependencies explicit.


137. Acceptance Criteria

Part 36 is complete when:

✓ Intelligence module exists
✓ FeatureDefinition exists
✓ FeatureValue exists
✓ FeatureStore exists
✓ FeatureCalculator exists
✓ SignalDefinition exists
✓ IntelligenceSignal exists
✓ SignalEvidence exists
✓ SignalCalculator exists
✓ SignalSource is explicit
✓ deterministic signals are distinguishable
✓ AI-inferred signals are distinguishable
✓ user-entered signals are distinguishable
✓ external signals are distinguishable
✓ ScoreDefinition exists
✓ ScoreValue exists
✓ ScoreComponent exists
✓ ScoreCalculator exists
✓ ScoreQuality exists
✓ scores are normalized
✓ score weights are explicit
✓ score components are explainable
✓ score bands are defined
✓ score bands are versioned
✓ historical scores are retained
✓ score trends can be calculated
✓ insignificant changes can be treated as stable
✓ feature calculations are versioned
✓ signal calculations are versioned
✓ score calculations are versioned
✓ evidence references are preserved
✓ score explanations expose evidence
✓ historical calculations remain reproducible
✓ freshness is tracked
✓ stale intelligence is detectable
✓ event-driven recalculation works
✓ scheduled recalculation works
✓ recalculation is idempotent
✓ dependency tracking exists
✓ only affected intelligence is recalculated
✓ tenant isolation is enforced
✓ cross-tenant features are impossible
✓ cross-tenant baselines are impossible
✓ cross-tenant score aggregation is impossible
✓ tenant baselines are supported
✓ minimum sample size is enforced
✓ unreliable baselines are marked unavailable
✓ Engagement Score exists
✓ Activity Momentum exists
✓ Staleness Score exists
✓ Stakeholder Coverage Score exists
✓ Task Execution Score exists
✓ Deal Velocity Score exists
✓ Opportunity Health Score exists
✓ Data Quality Score exists
✓ insufficient data is represented explicitly
✓ missing data does not silently become zero
✓ score completeness is available
✓ score change events exist
✓ health-band change events exist
✓ insignificant changes do not create event noise
✓ workflows can consume intelligence
✓ workflows cannot bypass action authorization
✓ agents can retrieve intelligence
✓ agents can retrieve score evidence
✓ agents do not need to reconstruct every signal from raw data
✓ ChatGPT can retrieve opportunity health
✓ ChatGPT can retrieve engagement scores
✓ ChatGPT can retrieve score history
✓ ChatGPT can explain scores using stored components
✓ ChatGPT does not invent replacement scores
✓ intelligence metrics exist
✓ freshness metrics exist
✓ recalculation metrics exist
✓ data quality metrics exist
✓ deterministic calculation tests pass
✓ tenant isolation tests pass
✓ evidence tests pass
✓ historical score tests pass
✓ versioning tests pass
✓ missing-data tests pass
✓ baseline tests pass
✓ workflow integration tests pass
✓ agent integration tests pass
✓ ChatGPT explanation tests pass

Most importantly:

Quorentra now has a reusable, deterministic and evidence-backed intelligence layer that converts raw CRM activity into structured business signals that ChatGPT, agents, workflows, dashboards, and users can consistently understand.


138. What We Have Achieved

The Quorentra architecture has now evolved through:

CRM Records
Knowledge
Grounded Retrieval
ChatGPT
Actions
Workflows
Agents
Intelligence

But architecturally, the runtime relationship is even more interesting:

CRM
Intelligence
ChatGPT / Agents / Workflows
Actions
CRM
Updated Intelligence

Quorentra is becoming a continuous intelligence system rather than merely a database with an AI chat interface.


139. A Practical Example

Imagine the following sequence.

Monday morning:

ACME Health:
68

Tuesday:

Customer meeting postponed.

Wednesday:

No response to proposal email.

Thursday:

Proposal revision task becomes overdue.

The intelligence layer recalculates:

Engagement:
72 → 55
Momentum:
68 → 43
Task Execution:
80 → 61
Health:
68 → 54

The health band changes:

Watch
At Risk

Quorentra emits:

opportunity.health_band_changed

A workflow sees the event.

The workflow launches:

Opportunity Risk Agent

The agent investigates the evidence.

It determines:

Primary Risk:
Unresolved proposal revision combined with declining customer engagement.

ChatGPT can then proactively surface:

ACME moved into the At Risk category today. Engagement has declined significantly, the proposal revision task is overdue, and the customer has not responded to the latest communication. The Opportunity Risk Agent recommends reviewing the proposal revision and contacting the customer before the end of the day.

That entire chain is now supported by the architecture we have built.


140. What Comes Next?

Quorentra now knows:

What happened
What changed
What signals exist
How scores are moving
Which opportunities are healthy
Which opportunities are deteriorating

But users will soon want something more powerful:

What should I do today?

Which five actions will have the greatest impact?

What should the salesperson do next on this opportunity?

Should we schedule a meeting, send a proposal revision, involve an executive sponsor, or wait?

This moves us from:

Intelligence

to:

Decision Intelligence

The next layer should convert signals, scores, CRM context, knowledge, and agent reasoning into structured Next-Best-Action recommendations.


Next: Part 37

Building the Next-Best-Action Recommendation Engine

Part 37 will introduce:

Recommendation
RecommendationType
RecommendationCandidate
RecommendationContext
RecommendationEvidence
RecommendationReason
RecommendationScore
RecommendationPriority
RecommendationConfidence
RecommendationUrgency
RecommendationImpact
RecommendationEffort
RecommendationRisk
RecommendationFreshness
RecommendationStatus
Candidate Generation
Rule-Based Candidates
Signal-Based Candidates
Agent-Generated Candidates
Recommendation Ranking
Recommendation Deduplication
Recommendation Suppression
Recommendation Expiration
Recommendation Conflicts
Next-Best-Action Selection
Top-N Recommendations
User Feedback
Accepted Recommendations
Rejected Recommendations
Dismissed Recommendations
Completed Recommendations
Recommendation Outcomes
Recommendation Learning Signals
Workflow Integration
Agent Integration
ChatGPT Integration
Approval-Gated Execution
Metrics
Testing
Evaluation

The architecture will evolve from:

CRM Data
Signals
Scores
Understanding

to:

CRM Data
Signals
Scores
Recommendation Candidates
Ranking
Next Best Action
ChatGPT
User Decision
Safe Execution

This will make Quorentra considerably more useful in day-to-day CRM work.

Instead of merely telling a salesperson:

ACME has a health score of 49.

Quorentra will be able to say:

ACME needs attention. The highest-priority next action is to finalize the requested migration timeline and contact the customer within 24 hours. The recommendation is based on declining engagement, an unresolved proposal requirement, and the approaching proposal deadline.

That is the next step toward turning Quorentra into a genuinely proactive, ChatGPT-native CRM intelligence platform.

Quorentra

Contact

Menu

Designed with WordPress

Discover more from Quorentra

Subscribe now to keep reading and get access to the full archive.

Continue reading