system-prompts-and-models-o.../dealix/tests/unit/test_revenue_company_os.py
Dealix Builder ef08649efe feat(autonomous-revenue-os): Dealix becomes a Category — Autonomous Revenue Company OS — 26 modules + 47 endpoints + 81 tests
# Dealix is no longer "a platform". It is a new category:
# An Autonomous Revenue Company OS that runs growth FOR Saudi businesses
# as if Growth + Sales + Partnerships + Customer Success + Strategy +
# Compliance + Data sat in one self-improving system.

Autonomous Service Operator (16 modules) — البوت المركزي
- intent_classifier: 16 supported intents (Arabic + English keywords; deterministic; no LLM)
- conversation_router: route_message + handle_message — single entry point that classifies, routes to handler, recommends a bundle, builds intake + initial pipeline
- session_state: 13 valid states + UUID-based sessions + audit history
- intake_collector: per-intent intake question sets + parse + validation
- approval_manager: Arabic approval cards (capped at 3 buttons) + decision processing (approve/edit/skip/reject including Arabic verbs)
- service_orchestrator: 11-step canonical pipeline (intake→data_check→targeting→contactability→strategy→drafting→approval→execution_or_export→tracking→proof→upsell)
- workflow_runner: advance + completion check
- tool_action_planner: HARD-BLOCKS linkedin.scrape_profile, linkedin.auto_dm, linkedin.auto_connect, social.scrape_followers; high-risk tools require approval; draft-safe tools return draft_only; unknown tools default to approval_required
- proof_pack_dispatcher: per-service Proof Pack envelope with required metrics
- upsell_engine: 3 deterministic verdicts (upsell_now / iterate_first / gentle_upsell) based on csat + pipeline + meetings
- whatsapp_renderer: render any card / approval / daily brief as WhatsApp draft (≤3 buttons, Arabic body, never live)
- operator_memory: in-process sessions + customer_facts + preferences + audit log (production = Supabase)
- service_bundles: 6 customer-facing bundles instead of 20 raw services (Growth Starter, Data to Revenue, Executive Growth OS, Partnership Growth, Local Growth OS, Full Growth Control Tower)
- executive_mode: CEO command center + daily brief + revenue risks (3) + next 3 moves
- client_mode: Growth Manager dashboard with 4 panels
- agency_mode: multi-client roster + co-branded Proof Pack + revenue share calc

Revenue Company OS (10 modules) — الذكاء عبر القنوات
- event_to_card: 13 event types → Arabic decision cards (email/whatsapp/form/review/payment/risk/partner/meeting/service.completed/...) each with title_ar/summary_ar/why_now_ar/recommended_action_ar/risk_level/buttons_ar (≤3)
- command_feed_engine: aggregate events for a customer + sort by risk (high first) + by_type and by_risk counts
- action_graph: 14 typed edges (signal_created_opportunity → message_triggered_reply → reply_led_to_meeting → meeting_led_to_proposal → proposal_led_to_payment → ...) with what_works_for_customer scoring (outcome edges weigh more)
- revenue_work_units: 19 RWU types (Salesforce-inspired): opportunity_created, draft_created, approval_collected, meeting_drafted, payment_received, risk_blocked, etc. + aggregate_work_units (counts/revenue/risks)
- channel_health: cross-channel reputation snapshot (email/whatsapp/linkedin) + overall_score + channels_at_risk
- opportunity_factory: turn (sector, city) into 5 opportunity cards via targeting_os.recommend_accounts + buying committee
- service_factory: instantiate any service for a customer (intake + workflow + quote)
- proof_ledger (revenue-tier, NOT platform_services.proof_ledger): customer-facing scoreboard with totals + summary_ar + by_type breakdown
- growth_memory: anonymized cross-customer aggregates — sector_message_winrate, sector_channel_winrate, common_objections, blocked_action_reasons, successful_playbooks; best_message_for_sector + best_channel_for_sector
- self_improvement_loop: weekly Arabic recommendations from real metrics (approval_rate, reply_rate, meeting_rate, blocked_actions, service_revenue) + best_service_id + next_experiment

Routers (2 new) — 47 endpoints
- /api/v1/operator/* (28): chat (message/decision/classify), sessions (new/transition/context/get), cards (approval/whatsapp/render), intake (questions/validate), service (start), tools (plan), proof-pack (dispatch), upsell (recommend/card), bundles (list/recommend), modes (ceo/ceo-daily-brief/ceo-risks/client/agency/agency-add-client/agency-revenue-share/agency-co-branded-proof), demos (whatsapp-daily-brief/proof-pack)
- /api/v1/revenue-os/* (19): command-feed (demo/build/events-ingest), work-units (types/build/aggregate/demo), proof-ledger/demo, action-graph (edge-types/demo), channel-health (snapshot/demo), opportunity-factory (run/demo), service-factory (instantiate/demo), growth-memory/demo, self-improvement (weekly-report/demo)

Tests (2 new files, 81 tests)
- test_autonomous_service_operator.py: 50 tests
  * 8 intent classification tests (want_more_customers, has_contact_list, partnerships, whatsapp, pricing, approve, unknown fallback)
  * 4 conversation router (recommends correct service per intent + bundle, processes approval decisions)
  * 4 session lifecycle (UUID, transition validation, memory store, context build)
  * 4 intake (questions per intent, validation detects missing fields, complete intake passes)
  * 4 approval (≤3 buttons, approve/skip Arabic, unknown decision returns error)
  * 5 tool planner (linkedin scrape blocked, auto_dm blocked, high-risk → approval, draft-safe → draft_only, unknown → approval_required)
  * 4 bundles (6 total, agency → partnership_growth, local → local_growth_os, default → growth_starter)
  * 7 modes (CEO Arabic, daily brief 3 decisions, 3 risks, client panels, agency aggregation, revenue share calc, co-branded includes both names)
  * 3 WhatsApp renderer (no live send, ≤3 buttons, Arabic morning text)
  * 4 proof + upsell (Proof Pack draft, upsell_now for strong, iterate_first for weak, ≤3 buttons)

- test_revenue_company_os.py: 31 tests
  * 4 event → card (email Arabic, low review high-risk, risk.blocked high, unknown → action_required)
  * 3 command feed (demo 8 events, sorts high-risk first, empty handling)
  * 4 RWUs (≥18 types, build validates, aggregate sums revenue, risks_blocked counted)
  * 4 action graph (≥12 edge types, validates type, demo 2 customers, what_works scoring)
  * 2 channel health (returns score, flags risky channel)
  * 2 opportunity factory (5 opps no live send, blocks unsafe in notes)
  * 3 service factory (instantiate known + unknown errors, demo 4 services)
  * 3 proof ledger (appends, rejects unknown, demo has revenue + risks)
  * 2 growth memory (top objections, best message per sector)
  * 3 self-improvement (low approval recommends fix, high blocked recommends review, returns best service)

Docs (1 new + 1 updated)
- AUTONOMOUS_REVENUE_COMPANY_OS.md (Arabic): 12-layer architecture + service bundles + safety + endpoints + competitive positioning
- DEALIX_100_PERCENT_LAUNCH_PLAN.md: added §44 Autonomous Revenue Company OS

Test results
- 81/81 new tests pass
- Full suite: 905 passed, 2 skipped (missing API keys, unrelated)
- 0 existing tests broken

Safety + integration
- All 47 new endpoints: live_send_allowed=False, approval_required=True
- LinkedIn scrape/auto-DM/auto-connect HARD-BLOCKED in tool_action_planner
- High-risk tools (whatsapp.send_message, gmail.send, calendar.insert_event, moyasar.charge, gbp.publish_review_reply, social.publish_dm, social.publish_post) → approval_required forced
- Cold WhatsApp blocked via existing contactability_matrix
- Operator memory hashes nothing yet — production must wire to security_curator.trace_redactor before any persistence
- 6 bundles unify the 12 productized services from Service Tower
- Modes integrate platform_services + intelligence_layer + service_excellence
- Action Graph + Revenue Work Units + Proof Ledger together form Dealix's Saudi Revenue Graph
- Self-improvement loop reads metrics that flow from agent_observability + growth_curator

Integration with everything before
- Autonomous Service Operator orchestrates Service Tower, Service Excellence OS, Targeting OS, Platform Services, Intelligence Layer
- Revenue Company OS reads from platform_services event_bus + intelligence_layer mission_engine + targeting_os reputation_guard
- Service factory uses service_tower.get_service + build_intake_questions + quote_service
- Opportunity factory uses targeting_os.recommend_accounts + map_buying_committee
- Channel health uses targeting_os.calculate_channel_reputation
- Tool planner integrates with platform_services.tool_gateway policies
- WhatsApp renderer aligns with launch_ops button caps
- Bundles map to service_tower upgrade_paths

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 17:50:32 +03:00

254 lines
8.8 KiB
Python

"""Unit tests for the Revenue Company OS layer."""
from __future__ import annotations
import pytest
from auto_client_acquisition.revenue_company_os import (
REVENUE_EDGE_TYPES,
REVENUE_WORK_UNIT_TYPES,
RevenueActionGraph,
RevenueProofLedger,
aggregate_work_units,
build_card_from_event,
build_channel_health_snapshot,
build_command_feed_for_customer,
build_growth_memory_demo,
build_opportunity_factory_demo,
build_revenue_action_graph_demo,
build_revenue_proof_ledger_demo,
build_revenue_work_unit,
build_service_factory_demo,
build_weekly_self_improvement_report,
instantiate_service,
revenue_os_command_feed_demo,
)
# ── Event → card ────────────────────────────────────────────
def test_email_event_returns_arabic_card():
card = build_card_from_event({
"event_type": "email.received",
"customer_id": "c1",
"payload": {"from": "ali@example.sa", "subject": "نطلب عرض"},
})
assert card["type"] == "email_lead"
assert any("؀" <= ch <= "ۿ" for ch in card["title_ar"])
assert card["live_send_allowed"] is False
def test_low_review_returns_high_risk():
card = build_card_from_event({
"event_type": "review.created",
"payload": {"rating": 1, "text": "تأخير في الرد"},
})
assert card["risk_level"] == "high"
def test_risk_blocked_event_high_risk():
card = build_card_from_event({
"event_type": "risk.blocked",
"payload": {"reason_ar": "محاولة cold WhatsApp"},
})
assert card["risk_level"] == "high"
assert "فهم" in card["buttons_ar"]
def test_unknown_event_returns_action_required():
card = build_card_from_event({"event_type": "totally.unknown"})
assert card["type"] == "action_required"
assert card["live_send_allowed"] is False
# ── Command feed ────────────────────────────────────────────
def test_command_feed_demo_has_8_events():
feed = revenue_os_command_feed_demo()
assert feed["feed_size"] == 8
def test_command_feed_sorts_high_risk_first():
feed = revenue_os_command_feed_demo()
cards = feed["cards"]
assert cards[0]["risk_level"] == "high"
def test_command_feed_for_customer_empty():
feed = build_command_feed_for_customer(customer_id="c1", events=[])
assert feed["feed_size"] == 0
assert feed["cards"] == []
# ── Revenue Work Units ──────────────────────────────────────
def test_rwu_types_count():
assert len(REVENUE_WORK_UNIT_TYPES) >= 18
def test_build_rwu_validates_type():
with pytest.raises(ValueError):
build_revenue_work_unit(unit_type="bogus")
def test_build_rwu_returns_valid_unit():
u = build_revenue_work_unit(
unit_type="opportunity_created",
customer_id="c1",
revenue_influenced_sar=18000,
)
assert u["unit_type"] == "opportunity_created"
assert u["revenue_influenced_sar"] == 18000.0
def test_aggregate_work_units_sums_revenue():
units = [
build_revenue_work_unit(unit_type="opportunity_created",
customer_id="c1", revenue_influenced_sar=10000),
build_revenue_work_unit(unit_type="opportunity_created",
customer_id="c1", revenue_influenced_sar=20000),
build_revenue_work_unit(unit_type="risk_blocked",
customer_id="c1", risk_level="high"),
]
agg = aggregate_work_units(units)
assert agg["total_units"] == 3
assert agg["total_revenue_influenced_sar"] == 30000.0
assert agg["risks_blocked"] == 1
# ── Revenue Action Graph ────────────────────────────────────
def test_action_graph_edge_types_count():
assert len(REVENUE_EDGE_TYPES) >= 12
def test_action_graph_add_edge_validates():
g = RevenueActionGraph()
with pytest.raises(ValueError):
g.add_edge(edge_type="bogus", src_id="a", dst_id="b")
def test_action_graph_demo_has_two_customers():
out = build_revenue_action_graph_demo()
assert "summary_a" in out
assert "summary_b" in out
assert out["summary_a"]["outcome_score"] > 0
def test_action_graph_what_works():
g = RevenueActionGraph()
g.add_edge(edge_type="proposal_led_to_payment", src_id="p1", dst_id="pay1",
customer_id="c1")
g.add_edge(edge_type="reply_led_to_meeting", src_id="r1", dst_id="m1",
customer_id="c1")
summary = g.what_works_for_customer("c1")
assert summary["total_edges"] == 2
assert summary["outcome_score"] > 0
# ── Channel Health ──────────────────────────────────────────
def test_channel_health_snapshot_returns_score():
out = build_channel_health_snapshot()
assert "channels" in out
assert "overall_score" in out
def test_channel_health_flags_risky_channel():
out = build_channel_health_snapshot(metrics_per_channel={
"email": {"bounce_rate": 0.20, "complaint_rate": 0.01,
"opt_out_rate": 0.30, "reply_rate": 0.001},
})
assert "email" in out["channels_at_risk"]
# ── Opportunity factory ─────────────────────────────────────
def test_opportunity_factory_returns_5_opps():
out = build_opportunity_factory_demo(limit=5)
assert out["count"] == 5
for opp in out["opportunities"]:
assert opp["live_send_allowed"] is False
def test_opportunity_factory_blocks_unsafe_actions():
out = build_opportunity_factory_demo()
notes = " ".join(out["do_not_do_ar"])
assert "scraping" in notes.lower() or "scraping" in notes
# ── Service factory ────────────────────────────────────────
def test_instantiate_service_known():
out = instantiate_service(
service_id="first_10_opportunities_sprint",
customer_id="c1",
)
assert "intake" in out
assert "workflow" in out
assert "quote" in out
assert out["live_send_allowed"] is False
def test_instantiate_service_unknown():
out = instantiate_service(service_id="totally_unknown")
assert "error" in out
def test_service_factory_demo_returns_4_services():
out = build_service_factory_demo()
assert len(out["instantiations"]) == 4
# ── Proof Ledger ────────────────────────────────────────────
def test_proof_ledger_appends_units():
led = RevenueProofLedger()
led.append_work_unit(build_revenue_work_unit(
unit_type="opportunity_created", customer_id="c1",
revenue_influenced_sar=10000,
))
summary = led.summary_for_customer("c1")
assert summary["totals"]["opportunities_created"] == 1
def test_proof_ledger_rejects_unknown_type():
led = RevenueProofLedger()
with pytest.raises(ValueError):
led.append_work_unit({"unit_type": "totally_bogus"})
def test_proof_ledger_demo_has_revenue():
out = build_revenue_proof_ledger_demo()
assert out["totals"]["revenue_influenced_sar"] > 0
assert out["totals"]["risks_blocked"] >= 2
# ── Growth Memory ───────────────────────────────────────────
def test_growth_memory_demo_has_top_objections():
out = build_growth_memory_demo()
assert out["summary"]["top_objections"]
def test_growth_memory_best_message():
out = build_growth_memory_demo()
assert out["best_message_training"]["sector"] == "training"
# ── Self-improvement loop ───────────────────────────────────
def test_self_improvement_low_approval_recommends_fix():
out = build_weekly_self_improvement_report(weekly_metrics={
"approval_rate": 0.10,
})
assert out["recommendations_ar"]
assert any("approval_rate" in r for r in out["recommendations_ar"])
def test_self_improvement_blocked_actions_high_recommends_review():
out = build_weekly_self_improvement_report(weekly_metrics={
"approval_rate": 0.5, "blocked_actions": 25,
})
assert any("منع" in r for r in out["recommendations_ar"])
def test_self_improvement_returns_best_service():
out = build_weekly_self_improvement_report(weekly_metrics={
"service_revenue_sar": {
"first_10_opportunities_sprint": 1500,
"growth_os_monthly": 5000,
},
})
assert out["best_service_id"] == "growth_os_monthly"