mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 07:19:35 +00:00
Locks Dealix's positioning forever and closes the operational gap between "great product" and "great customer experience": onboarding, connectors, support SLA, incidents, customer success cadence, and companies/marketers landing pages. Positioning Lock (3 docs) - POSITIONING_LOCK.md (Arabic): Saudi Revenue Execution OS category lock; one-liner; primary buyers (companies + agencies/marketers); wedge (First 10 Opportunities + Proof Pack); 5 approved claims; 5 prohibited categories; 5 modes; 5 bundles; 6 "what Dealix is NOT" rules - PROHIBITED_CLAIMS.md (Arabic): 8 categories of forbidden marketing language (guaranteed results, scraping, full automation, bypass approvals, competitor attacks, legal/financial promises, medical language, exaggerated speed) + technical enforcement (safety_eval + tone_eval + quality_review_gate + tool_action_planner + test_positioning_lock.py) - APPROVED_MARKET_MESSAGING.md (Arabic): tagline + 30-second elevator pitch + 5 headlines + competitor positioning table + 4-segment outreach templates + LinkedIn/X social posts + slogan bank Customer Ops (6 modules) - onboarding_checklist: 8-step Pilot onboarding (select_goal → select_bundle → company_intake → connect_channels → upload_or_source → risk_review → first_service_run → first_proof_pack) with progress tracking + state advancement - connector_setup_status: 11 connectors (Gmail/Calendar/Sheets/Moyasar/WhatsApp/Forms/LinkedIn-LeadForms/GBP/CRM/Meet/Instagram) each with default_mode (draft_only/manual/ingest_only/approved_execute), launch phase, and blocking flag; ready_for_first_service gate requires no blocking connectors missing AND ≥1 connected - support_ticket_router: 4-tier P0/P1/P2/P3 classification with Arabic+English keyword matching; auto-classifies "تسريب", "إرسال بدون موافقة", "بدون موافقتي", "live charge", "unauthorized" as P0; per-priority Arabic first-response templates; SLA targets per priority - sla_tracker: SLA targets per priority (P0=30min/4h, P1=2h/24h, P2=8h/72h, P3=24h/1week); record_sla_event with strict event-type validation; classify_sla_breach for individual tickets; build_sla_health_report aggregates with verdict (healthy/watch/critical based on breach_rate) - customer_success_cadence: 6 cadence types (weekly_check_in, monthly_proof_review, QBR, at_risk_alert, renewal_30/7_day); build_at_risk_alert with risk_score 0..100 from days_inactive + drafts_pending + last_proof_pack_days_ago; build_customer_success_plan with 30-day per-bundle cadences (growth_starter, executive_growth_os, partnership_growth) - incident_router: SEV1/SEV2/SEV3 with first_action_minutes + comm_cadence; auto-SEV1 on has_data_leak OR has_unauthorized_send; SEV2 on affected_customers≥5; canonical 5-step response plan (freeze live actions / notify founder / create incident channel / review Action Ledger / PDPL 72h notification) + per-severity additional steps + post-mortem template New Operator Modes (2) - self_growth_mode: re-exports targeting_os.self_growth_mode (DEALIX_ICP_FOCUSES, recommend_dealix_targets, build_self_growth_daily_brief, build_weekly_learning_report) + operator-tier reminders (no cold WhatsApp even for Dealix itself, all drafts approval-first, no scraping) - service_delivery_mode: orchestrates service_tower workflow + revenue_launch.pilot_delivery + customer_ops.sla_tracker; build_service_delivery_brief (per-service template), build_sla_status_for_delivery (breach detection on open tickets), build_post_delivery_handoff (5-step transition to Customer Success cadence) Router (1 new) — 20 endpoints - /api/v1/customer-ops/* — onboarding (checklist/update-step/demo), connectors (catalog/summary/update/demo), support (priorities/classify/route/first-response), sla (event/classify-breach/health-report/health-report-demo), incidents (triage/response-plan), cs (weekly-check-in/at-risk-alert/success-plan) Customer-facing pages (1 new, 1 already-existed-preserved) - landing/companies.html (NEW): Saudi B2B companies pitch — Approval-first, no scraping, no cold WhatsApp; 4 bundles (Growth Starter / Data to Revenue / Executive Growth OS / Full Growth Control Tower); Proof Pack section; safety + compliance section - landing/marketers.html (existed): preserved as-is — agency/marketers Agency Growth OS path Tests (2 new files, 44 tests) - test_customer_ops.py: 31 tests * 4 onboarding (8 steps, advancement, unknown step error, complete-all) * 5 connectors (critical connectors present, blocking_missing detection, ready gate, validation, write) * 8 support (P0 security, P0 unauthorized send, P1 service down, P2 connector, P3 default, empty input, route includes SLA, P0 first-response Arabic with 30 min) * 6 SLA (event validates, log appends, breach detection within/exceeded targets, health report aggregation, critical verdict) * 4 incidents (data leak SEV1, unauthorized send SEV1, ≥5 customers SEV2, single customer SEV3, SEV1 plan includes PDPL) * 4 customer success (weekly check-in talking points Arabic, at-risk high severity, at-risk low severity, success plan per bundle including growth_starter and executive_growth_os Founder Shadow Board) - test_positioning_lock.py: 13 tests * positioning_lock.md exists with category + "ليس CRM" + "ليس بوت" * prohibited_claims.md exists with "نضمن" + "scraping" * approved_market_messaging.md has Approval-first + PDPL + Saudi Tone + Proof Pack * landing pages contain NO positive forbidden claims (negative restatements like "no auto-DM" in safety sections allowed) * companies.html includes "Approval-first" + "Proof Pack" * agency-partner.html OR marketers.html exists * private-beta.html does NOT promise guarantees * REVENUE_TODAY_PLAYBOOK emphasizes Approval-first * positioning_lock lists all 5 bundles * positioning_lock lists all 5 modes (CEO + Growth Manager + Agency Partner + Self-Growth + Service Delivery) Customer Ops Docs (5 new) - ONBOARDING_RUNBOOK.md (Arabic): 8 onboarding steps + day-by-day Day1-Day5 + 11 connector states + acceptance criteria - SUPPORT_SLA.md (Arabic): 4 priority tiers + auto-classification keywords + Arabic first-response templates + weekly review process - INCIDENT_RESPONSE.md (Arabic): SEV1/SEV2/SEV3 logic + canonical response plan + per-severity additional steps + post-mortem template + Arabic communication templates + auto-actions - CUSTOMER_SUCCESS_PLAYBOOK.md (Arabic): cadence types + weekly agenda (25 min) + at-risk scoring formula + per-bundle cadence + QBR + renewal flow + health score formula - CONNECTOR_SETUP_GUIDES.md (Arabic): all 11 connectors with scopes + step-by-step + acceptance criteria + troubleshooting table Test results - 44/44 new tests pass - Full suite: 949 passed, 2 skipped (missing API keys, unrelated) - 0 existing tests broken Safety + integration - All 20 customer-ops endpoints: approval_required=True, live_send_allowed=False - support_ticket_router HARD-CLASSIFIES "تسريب", "إرسال بدون موافقة", "live charge", "unauthorized" as P0 (founder owner, 30-min first response) - incident_router auto-promotes to SEV1 on has_data_leak or has_unauthorized_send (regardless of affected_customers count) - onboarding_checklist requires WhatsApp connector (blocking) before ready_for_first_service - connector_setup_status default_mode is draft_only/manual/ingest_only — never live - Positioning Lock test_positioning_lock.py enforces: * 5 bundles must be listed in POSITIONING_LOCK.md * 5 modes must be listed * landing pages must not contain positive forbidden claims (8 phrases) * companies.html must mention Approval-first + Proof Pack - self_growth_mode reminds operator: no cold WhatsApp even for Dealix itself - service_delivery_mode integrates SLA tracker before declaring delivery success Integration with everything before - Customer Ops onboarding integrates Service Bundles (autonomous_service_operator.service_bundles) - Customer Ops connectors mirror connector_catalog risk_levels + add operational state machine - Support classifier integrates with security_curator (P0 on secret leaks) + revenue_launch.payment_manual_flow (P0 on unauthorized charge) - Customer Success metrics flow from agent_observability + revenue_launch.proof_pack_template - Service Delivery Mode wires service_tower.workflow + revenue_launch.pilot_delivery + sla_tracker into one pipeline - Self-Growth Mode wraps targeting_os.self_growth_mode with operator-tier safety reminders - Companies + Marketers pages enforce POSITIONING_LOCK headlines Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
269 lines
8.8 KiB
Python
269 lines
8.8 KiB
Python
"""Unit tests for Customer Ops."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from auto_client_acquisition.customer_ops import (
|
|
SUPPORT_PRIORITIES,
|
|
SUPPORTED_CONNECTORS,
|
|
build_at_risk_alert,
|
|
build_connector_setup_summary,
|
|
build_customer_success_plan,
|
|
build_first_response_template,
|
|
build_incident_response_plan,
|
|
build_onboarding_checklist,
|
|
build_sla_health_report,
|
|
build_weekly_check_in,
|
|
classify_sla_breach,
|
|
classify_ticket_priority,
|
|
record_sla_event,
|
|
route_ticket,
|
|
triage_incident,
|
|
update_connector_status,
|
|
update_onboarding_step,
|
|
)
|
|
|
|
|
|
# ── Onboarding ───────────────────────────────────────────────
|
|
def test_onboarding_checklist_has_8_steps():
|
|
out = build_onboarding_checklist(customer_id="c1")
|
|
assert out["total_steps"] == 8
|
|
assert out["current_step_id"] == "select_goal"
|
|
|
|
|
|
def test_update_onboarding_step_completes():
|
|
cl = build_onboarding_checklist(customer_id="c1")
|
|
cl = update_onboarding_step(cl, step_id="select_goal", completed=True)
|
|
assert cl["progress_pct"] == 12.5
|
|
assert cl["current_step_id"] == "select_bundle"
|
|
|
|
|
|
def test_update_onboarding_step_unknown():
|
|
cl = build_onboarding_checklist(customer_id="c1")
|
|
cl = update_onboarding_step(cl, step_id="bogus_step")
|
|
assert "error" in cl
|
|
|
|
|
|
def test_complete_all_onboarding_steps():
|
|
cl = build_onboarding_checklist(customer_id="c1")
|
|
for s in list(cl["steps"]):
|
|
cl = update_onboarding_step(cl, step_id=s["id"], completed=True)
|
|
assert cl["progress_pct"] == 100.0
|
|
assert cl["current_step_id"] == "done"
|
|
|
|
|
|
# ── Connectors ───────────────────────────────────────────────
|
|
def test_supported_connectors_includes_critical():
|
|
keys = {c["key"] for c in SUPPORTED_CONNECTORS}
|
|
for required in ("gmail", "google_calendar", "moyasar", "whatsapp_cloud",
|
|
"google_sheets", "website_forms", "linkedin_lead_forms"):
|
|
assert required in keys
|
|
|
|
|
|
def test_connector_summary_with_blocking_missing():
|
|
out = build_connector_setup_summary(
|
|
customer_id="c1",
|
|
statuses={"gmail": {"state": "connected_draft_only"}},
|
|
)
|
|
assert "whatsapp_cloud" in out["blocking_missing"]
|
|
assert out["ready_for_first_service"] is False
|
|
|
|
|
|
def test_connector_summary_ready():
|
|
out = build_connector_setup_summary(
|
|
customer_id="c1",
|
|
statuses={
|
|
"gmail": {"state": "connected_draft_only"},
|
|
"whatsapp_cloud": {"state": "connected_draft_only"},
|
|
},
|
|
)
|
|
assert out["ready_for_first_service"] is True
|
|
|
|
|
|
def test_update_connector_status_validates():
|
|
statuses: dict = {}
|
|
with pytest.raises(ValueError):
|
|
update_connector_status(statuses, connector_key="gmail",
|
|
state="totally_invalid")
|
|
|
|
|
|
def test_update_connector_status_writes():
|
|
statuses: dict = {}
|
|
update_connector_status(statuses, connector_key="gmail",
|
|
state="connected_draft_only")
|
|
assert statuses["gmail"]["state"] == "connected_draft_only"
|
|
|
|
|
|
# ── Support routing ──────────────────────────────────────────
|
|
def test_classify_p0_for_security_keywords():
|
|
out = classify_ticket_priority("اكتشفت تسريب في trace logs")
|
|
assert out["priority"] == "P0"
|
|
|
|
|
|
def test_classify_p0_for_unauthorized_send():
|
|
out = classify_ticket_priority("Dealix أرسل رسالة بدون موافقتي")
|
|
assert out["priority"] == "P0"
|
|
|
|
|
|
def test_classify_p1_for_service_down():
|
|
out = classify_ticket_priority("Pilot stopped working today")
|
|
assert out["priority"] == "P1"
|
|
|
|
|
|
def test_classify_p2_for_connector_issue():
|
|
out = classify_ticket_priority("My Gmail connector won't authenticate")
|
|
assert out["priority"] == "P2"
|
|
|
|
|
|
def test_classify_p3_default():
|
|
out = classify_ticket_priority("سؤال بسيط عن الأسعار")
|
|
assert out["priority"] == "P3"
|
|
|
|
|
|
def test_classify_empty_returns_p3():
|
|
out = classify_ticket_priority("")
|
|
assert out["priority"] == "P3"
|
|
|
|
|
|
def test_route_ticket_includes_sla():
|
|
out = route_ticket(text="تسريب أمان", customer_id="c1")
|
|
assert out["priority"] == "P0"
|
|
assert out["sla"]["first_response_minutes"] == 30
|
|
assert out["live_send_allowed"] is False
|
|
|
|
|
|
def test_first_response_p0_arabic():
|
|
out = build_first_response_template("P0")
|
|
assert "30 دقيقة" in out["body_ar"]
|
|
assert out["live_send_allowed"] is False
|
|
|
|
|
|
def test_support_priorities_count():
|
|
assert len(SUPPORT_PRIORITIES) == 4
|
|
|
|
|
|
# ── SLA ──────────────────────────────────────────────────────
|
|
def test_sla_event_validates():
|
|
with pytest.raises(ValueError):
|
|
record_sla_event(ticket_id="t1", priority="P0", event="bogus")
|
|
|
|
|
|
def test_sla_event_appends_to_log():
|
|
log: list = []
|
|
record_sla_event(ticket_id="t1", priority="P0", event="opened", log=log)
|
|
assert len(log) == 1
|
|
|
|
|
|
def test_classify_breach_within_target():
|
|
out = classify_sla_breach(
|
|
priority="P0", minutes_to_first_response=20, hours_to_resolve=3,
|
|
)
|
|
assert out["breached"] is False
|
|
|
|
|
|
def test_classify_breach_exceeded():
|
|
out = classify_sla_breach(
|
|
priority="P0", minutes_to_first_response=120, hours_to_resolve=10,
|
|
)
|
|
assert out["breached"] is True
|
|
assert len(out["breaches"]) == 2
|
|
|
|
|
|
def test_sla_health_report_aggregates():
|
|
out = build_sla_health_report(tickets=[
|
|
{"priority": "P0", "first_response_min": 12, "resolution_hours": 2},
|
|
{"priority": "P1", "first_response_min": 90, "resolution_hours": 18},
|
|
{"priority": "P3", "first_response_min": 1500, "resolution_hours": 200},
|
|
])
|
|
assert out["total_tickets"] == 3
|
|
assert out["total_breached"] == 1 # only P3 breached
|
|
|
|
|
|
def test_sla_health_verdict_critical():
|
|
out = build_sla_health_report(tickets=[
|
|
{"priority": "P0", "first_response_min": 60, "resolution_hours": 10},
|
|
{"priority": "P0", "first_response_min": 120, "resolution_hours": 20},
|
|
{"priority": "P0", "first_response_min": 180, "resolution_hours": 30},
|
|
{"priority": "P0", "first_response_min": 240, "resolution_hours": 40},
|
|
])
|
|
assert out["verdict"] == "critical"
|
|
|
|
|
|
# ── Incidents ───────────────────────────────────────────────
|
|
def test_triage_data_leak_is_sev1():
|
|
out = triage_incident(
|
|
title="Possible data exposure",
|
|
has_data_leak=True,
|
|
)
|
|
assert out["severity"] == "SEV1"
|
|
|
|
|
|
def test_triage_unauthorized_send_is_sev1():
|
|
out = triage_incident(
|
|
title="Unauthorized message",
|
|
has_unauthorized_send=True,
|
|
)
|
|
assert out["severity"] == "SEV1"
|
|
|
|
|
|
def test_triage_many_customers_is_sev2():
|
|
out = triage_incident(
|
|
title="Service outage",
|
|
affected_customers=10,
|
|
)
|
|
assert out["severity"] == "SEV2"
|
|
|
|
|
|
def test_triage_single_customer_is_sev3():
|
|
out = triage_incident(title="Customer X has issue", affected_customers=1)
|
|
assert out["severity"] == "SEV3"
|
|
|
|
|
|
def test_incident_response_plan_sev1_includes_pdpl():
|
|
out = build_incident_response_plan(severity="SEV1")
|
|
text = " ".join(out["plan_ar"])
|
|
assert "PDPL" in text
|
|
|
|
|
|
# ── Customer Success ────────────────────────────────────────
|
|
def test_weekly_check_in_arabic():
|
|
out = build_weekly_check_in(
|
|
customer_id="c1", company_name="Acme",
|
|
metrics={"drafts_approved": 5, "replies": 2,
|
|
"meetings": 1, "risks_blocked": 3, "pipeline_sar": 18000},
|
|
)
|
|
assert out["type"] == "weekly_check_in"
|
|
assert any("Pipeline" in tp for tp in out["talking_points_ar"])
|
|
|
|
|
|
def test_at_risk_alert_high_severity():
|
|
out = build_at_risk_alert(
|
|
customer_id="c1", days_inactive=20,
|
|
drafts_pending=15, last_proof_pack_days_ago=21,
|
|
)
|
|
assert out["severity"] == "high"
|
|
assert out["risk_score"] >= 60
|
|
|
|
|
|
def test_at_risk_alert_low_severity():
|
|
out = build_at_risk_alert(
|
|
customer_id="c1", days_inactive=2,
|
|
drafts_pending=1, last_proof_pack_days_ago=3,
|
|
)
|
|
assert out["severity"] == "low"
|
|
|
|
|
|
def test_customer_success_plan_for_growth_starter():
|
|
out = build_customer_success_plan(
|
|
customer_id="c1", bundle_id="growth_starter",
|
|
)
|
|
assert any("Day 1" in line for line in out["cadence_ar"])
|
|
|
|
|
|
def test_customer_success_plan_for_executive():
|
|
out = build_customer_success_plan(
|
|
customer_id="c1", bundle_id="executive_growth_os",
|
|
)
|
|
assert any("Founder Shadow Board" in line for line in out["cadence_ar"])
|