From 342bcf8ea514292e082f104b9e443ee7dd4df0c6 Mon Sep 17 00:00:00 2001
From: Dealix Builder
Date: Fri, 1 May 2026 18:39:36 +0300
Subject: [PATCH] =?UTF-8?q?feat(paid-beta):=20operational=20layer=20for=20?=
=?UTF-8?q?first=20499=20SAR=20=E2=80=94=20playbook=20+=20workflow=20+=20b?=
=?UTF-8?q?oard=20+=20scorecard=20+=20landing=20CTA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Move from GO_PRIVATE_BETA (technical readiness) to PAID_BETA_READY
(first revenue) — operational, not architectural.
Deliverables:
- docs/PAID_BETA_OPERATING_PLAYBOOK.md
10-section Arabic playbook: gate to Paid Beta, 7-day day-by-day
plan (Staging → Outreach → Demos → Diagnostic → Pilot Sale →
Pilot Day1/Day2 → Proof+Upsell), weekly targets (50-70 messages /
5-10 replies / 3-5 demos / 1+ payment), 8 hard operational rules,
daily cadence, what NOT to add, Public Launch criteria.
- docs/FIRST_PILOT_DELIVERY_WORKFLOW.md
48-hour Arabic Pilot delivery: T+0 intake (15 fields) → T+24
Free Diagnostic (3 opportunities + 1 Arabic message + 1 risk + 1
service recommendation) → T+48 Pilot 499 (10 opportunities + 7-day
follow-up plan + Proof Pack) → T+7 final Proof Pack + 30min review +
3 upgrade paths. Pilot success criteria + 8-row metrics table.
- docs/PRIVATE_BETA_OPERATING_BOARD.md
15-column Sheet template (company, person, segment, source, channel,
message_sent, reply_status, demo_booked, diagnostic_sent,
pilot_offered, price, paid, proof_pack_sent, next_step, notes) +
status flow + ICP distribution + 3-wave follow-up templates +
daily routine + PDPL privacy rules + CSV header.
- landing/private-beta.html
Pilot 499 SAR offer prominent at top (badge + hero CTA), dedicated
3-card pricing section (Pilot 499 / Free Diagnostic / Growth OS
Monthly 2,999), 7-day refund/case-study guarantee, mailto CTAs
with prefilled subject + body, removed duplicate pricing block.
- scripts/paid_beta_daily_scorecard.py (274 lines)
argparse with --messages, --replies, --demos, --pilots, --payments,
--proof-packs, --as-of, --json. Computes reply_rate / demo_rate /
pilot_rate / payment_rate, daily verdict (ON_TRACK / BEHIND /
OFF_TRACK), weekly verdict (BLOCKERS / STRETCH_PENDING /
WEEKLY_TARGETS_HIT), and rule-based next_actions in Arabic.
Targets: 50-70 messages / 5-15 replies / 3-7 demos / 2-3 pilots /
1-2 paid / 1+ proof pack per week.
- tests/unit/test_paid_beta_scorecard.py
12 tests: zero-input, on-track day, tone-action trigger, payment
→ proof-pack action, full-week target hit, conversion rates,
Arabic text rendering, JSON validity, CLI text/json modes,
--as-of today/explicit.
Hard rules (unchanged):
- No live WhatsApp / Gmail / Calendar send without env flag + approval.
- No Moyasar API charge — manual invoice/payment-link only.
- No LinkedIn scraping / auto-DM — Lead Gen Forms + manual outreach.
- No cold WhatsApp without opt-in (PDPL hard-block).
- Every message passes safety_eval + saudi_tone_eval.
- Every action recorded in Action Ledger.
Validation:
- python -m compileall api auto_client_acquisition: clean.
- pytest tests/unit (excl. tenacity-dep tests): 950 passed, 2 skipped.
- python scripts/smoke_inprocess.py: SMOKE_INPROCESS_OK (8/8 endpoints).
- python scripts/paid_beta_daily_scorecard.py text + --json: both render
correctly with Arabic + verdict + next_actions.
- tests/unit/test_positioning_lock.py: 10 passed (no prohibited
phrases introduced in updated landing/private-beta.html).
Test count: 949 → 962 (+12 new, 1 prior already counted).
Co-Authored-By: Claude Opus 4.7 (1M context)
---
dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md | 260 +++++++++++++++++
dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md | 206 +++++++++++++
dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md | 183 ++++++++++++
dealix/landing/private-beta.html | 103 ++++---
dealix/scripts/paid_beta_daily_scorecard.py | 274 ++++++++++++++++++
dealix/tests/unit/test_paid_beta_scorecard.py | 125 ++++++++
6 files changed, 1116 insertions(+), 35 deletions(-)
create mode 100644 dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md
create mode 100644 dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md
create mode 100644 dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md
create mode 100644 dealix/scripts/paid_beta_daily_scorecard.py
create mode 100644 dealix/tests/unit/test_paid_beta_scorecard.py
diff --git a/dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md b/dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md
new file mode 100644
index 00000000..2839468e
--- /dev/null
+++ b/dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md
@@ -0,0 +1,260 @@
+# First Pilot Delivery Workflow (48 ساعة)
+
+> **القاعدة:** كل Pilot 499 ريال يُسلَّم خلال 48 ساعة. لا يتجاوز. لا live send. لا Moyasar API. لا scraping. كل خطوة approval-first.
+
+---
+
+## 1. الإطار العام
+
+```
+T+0 intake (15 دقيقة)
+T+24 Free Diagnostic (3 فرص + رسالة + مخاطرة + توصية)
+T+48 Pilot Delivery (10 فرص + رسائل + متابعة + Proof Pack)
+T+7 Follow-up Wave (نتائج + اقتراح Growth OS أو case study)
+```
+
+**الهدف الفعلي:** أن يقول العميل "هذا أفضل من شغل وكالتنا الحالية" خلال 48 ساعة.
+
+---
+
+## 2. T+0 — Intake (15 دقيقة)
+
+### الحقول المطلوبة
+
+```
+company_name مثال: "حلول الراحة للأثاث"
+sector construction | clinics | logistics | f&b | retail | edtech | software | other
+city الرياض / جدة / الدمام / الخبر / مكة / المدينة / الطائف
+ticket_size_sar 5_000 | 25_000 | 100_000 | 500_000+
+contact_name اسم صاحب القرار
+contact_role owner | gm | head_of_sales | head_of_marketing | other
+icp_today وصف العميل المثالي اليوم (3 أسطر)
+last_3_clients اسم القطاع + المدينة + حجم الصفقة (إن وُجد)
+channels_used whatsapp | gmail | linkedin_lead_forms | website_forms | calls
+data_in_hand crm | sheet | none
+why_now لماذا الآن؟ (3 أسطر — أول inbound dropped, slow Q, agency churn, ...)
+red_flags قطاعات/مناطق/أنواع لا يخدمها
+opt_in_status هل عنده WhatsApp opt-in موثق؟ نعم/لا
+```
+
+### مصدر الـ intake
+- نموذج Google Form بسيط، أو
+- محادثة WhatsApp/Email مكتوبة (نسخها يدوياً).
+
+### بعد الـ intake
+1. سجّل العميل في `PRIVATE_BETA_OPERATING_BOARD.md`.
+2. أنشئ مجلد `pilots//` فيه: `intake.md`, `diagnostic.md`, `pilot.md`, `proof_pack.md`.
+3. أرسل تأكيد عربي:
+ > وصلني intake. سأرسل لك Free Diagnostic خلال 24 ساعة. فيه 3 فرص محددة + رسالة جاهزة + مخاطرة موجودة + توصية. بدون أي إرسال خارجي بدون موافقتك.
+
+---
+
+## 3. T+24 — Free Diagnostic
+
+### المحتوى المطلوب
+1. **3 فرص B2B محددة بأسماء حقيقية**
+ - اسم الشركة + قطاعها + مدينتها + سبب الاهتمام (why_now).
+ - كل فرصة لها صاحب قرار مرشح (اسم + دور).
+ - كل فرصة لها قناة موصى بها (whatsapp opt-in / gmail / website_form / linkedin lead form / call).
+
+2. **رسالة عربية جاهزة (تحت 80 كلمة)**
+ - نبرة سعودية طبيعية (لا "تحية طيبة وبعد"، لا synergy).
+ - تستخدم اسم العميل + قطاعه + سبب التواصل.
+ - تنتهي بـ CTA واضح (مكالمة 12 دقيقة / لقاء قهوة / تجربة مجانية).
+ - تمر `safety_eval` + `saudi_tone_eval` قبل التسليم.
+
+3. **مخاطرة موجودة الآن**
+ - تسريب data، WhatsApp بدون opt-in، إيميل bounce rate عالي، رسالة فيها claim طبي/مالي ممنوع.
+ - مع توصية إصلاح من `incident_router` أو `support_sla`.
+
+4. **توصية خدمة واحدة من Service Tower**
+ - First 10 Opportunities Sprint (499) أو
+ - Growth Diagnostic Pro (1,500) أو
+ - Partnership Sprint (2,500) أو
+ - Growth OS Monthly (2,999/شهر).
+
+### Endpoints المستخدمة
+```
+POST /api/v1/customer-ops/onboarding/checklist
+POST /api/v1/service-excellence/review/all
+POST /api/v1/operator/bundles
+GET /api/v1/launch/private-beta/offer
+```
+
+### قالب Diagnostic (عربي)
+
+```
+Diagnostic —
+
+أهم 3 فرص لك هذا الأسبوع:
+1. <اسم الشركة 1> — <قطاع> — <مدينة>
+ لماذا الآن: ...
+ صاحب القرار: ...
+ القناة: ...
+2. ...
+3. ...
+
+رسالة عربية جاهزة (تحت 80 كلمة):
+"<الرسالة>"
+
+مخاطرة موجودة الآن:
+- ...
+التوصية: ...
+
+الخدمة الموصى بها:
+- First 10 Opportunities Sprint — 499 ريال — يبدأ غداً.
+- نسلّم: 10 فرص + 10 رسائل + خطة متابعة 7 أيام + Proof Pack.
+
+— Bassam
+```
+
+### بعد الإرسال
+- حدّث `Operating Board`: `diagnostic_sent = today`, `next_step = pilot_offer`.
+- تابع بعد 24 ساعة بقالب Follow-up #1.
+
+---
+
+## 4. T+48 — Pilot Delivery 499
+
+### المحتوى المطلوب
+1. **10 فرص B2B**
+ - كل فرصة فيها: company_name, sector, city, decision_maker, role, channel, why_now (3 أسطر), رسالة عربية جاهزة (تحت 80 كلمة), risk_score (0..100), contactability (1..5).
+
+2. **خطة متابعة 7 أيام**
+ - يوم 1: الرسالة الأولى.
+ - يوم 3: رسالة متابعة #1 (لو ما رد).
+ - يوم 5: رسالة متابعة #2 (تحويل قناة لو احتاج — مثلاً WhatsApp إلى Email).
+ - يوم 7: قرار: keep / drop / nurture.
+
+3. **Proof Pack مختصر**
+ ```
+ opportunities_created: 10
+ drafts_created: 10
+ approvals_needed: 10
+ risks_blocked:
+ recommended_next_action:
+ upgrade_offer: "نواصل شهرياً مقابل 2,999 ريال — أول شهر بسعر 1,999."
+ ```
+
+### Endpoints المستخدمة
+```
+POST /api/v1/operator/chat/message
+POST /api/v1/customer-ops/connectors/summary
+POST /api/v1/revenue-launch/payment/invoice-instructions
+POST /api/v1/revenue-launch/proof-pack/template
+GET /api/v1/service-excellence/review/all
+```
+
+### قالب Pilot Delivery (عربي مختصر)
+
+```
+First 10 Opportunities Sprint —
+
+10 فرص أولى لك:
+1. ... | ... | ... | "<رسالة جاهزة>"
+2. ...
+...
+10. ...
+
+خطة متابعة 7 أيام:
+- يوم 1: إرسال أول دفعة (5 رسائل) بعد اعتمادك.
+- يوم 3: متابعة الرسائل بدون رد.
+- يوم 5: تحويل قناة لمن لم يرد (Email → WhatsApp opt-in).
+- يوم 7: قرار keep/drop/nurture.
+
+Proof Pack:
+- opportunities_created: 10
+- drafts_created: 10
+- approvals_needed: 10 (تنتظر اعتمادك)
+- risks_blocked:
+
+التوصية بعد 7 أيام:
+- Growth OS Monthly (2,999 ر.س/شهر) — نواصل من حيث وقفنا.
+- أو Case Study مجاني مقابل اقتباس.
+
+— Bassam
+```
+
+### بعد الإرسال
+- حدّث Operating Board: `pilot_offered = today`, `price = 499`, `paid = pending`.
+- أرسل Moyasar invoice manual (URL يدوي).
+- تابع تأكيد الدفع.
+
+---
+
+## 5. T+7 — Follow-up Wave + Proof Pack النهائي
+
+### المحتوى
+1. **Proof Pack نهائي**
+ - leads_count + drafts_approved + replies + meetings_booked + pipeline_sar + risks_blocked.
+ - chart مبسط: messages_sent vs replies vs meetings.
+ - أهم 3 رسائل اعتمدها العميل (مع التعديلات إن وُجدت).
+ - أهم 3 مخاطر تم منعها تلقائياً.
+
+2. **جلسة مراجعة 30 دقيقة**
+ - "ما الذي اشتغل؟ ما الذي لم يشتغل؟"
+ - "نواصل شهرياً، ولا نوقف، ولا نحوّل لـ case study؟"
+
+3. **3 مسارات للترقية**
+ - **Growth OS Monthly** (2,999 ر.س/شهر) — استمرار شهري.
+ - **Partnership Sprint** (2,500 ر.س لمرة) — لو فيه شراكات قابلة.
+ - **Case Study + Referral** — مقابل اسم وكالة/عميل آخر يحتاج Pilot.
+
+### Endpoints المستخدمة
+```
+POST /api/v1/customer-ops/cs/weekly-check-in
+POST /api/v1/customer-ops/cs/success-plan
+POST /api/v1/revenue-launch/proof-pack/template
+GET /api/v1/service-excellence/review/all
+```
+
+---
+
+## 6. ما لا يحدث في Pilot Delivery
+
+- لا live WhatsApp send بدون env flag + اعتماد.
+- لا live Gmail send بدون env flag + اعتماد.
+- لا Moyasar charge من API — invoice/payment-link manual فقط.
+- لا scraping LinkedIn — Lead Gen Forms + استرشادي فقط.
+- لا cold WhatsApp بدون opt-in — PDPL hard-block.
+- لا تجاوز 48 ساعة — لو فيه عذر، نعتذر بدل أن نتأخر.
+- لا تخفيض السعر بدون موافقة المؤسس — 499 ثابت.
+- لا توسيع scope في الـ Pilot — 10 فرص فقط، الزيادة في Growth OS.
+
+---
+
+## 7. شروط نجاح Pilot
+
+- [ ] Diagnostic سُلّم خلال 24 ساعة.
+- [ ] Pilot سُلّم خلال 48 ساعة.
+- [ ] العميل اعتمد ≥3 رسائل من العشرة.
+- [ ] Proof Pack وصل خلال 7 أيام.
+- [ ] جلسة مراجعة 30 دقيقة تمت.
+- [ ] 1+ case study أو 1+ Growth OS subscription.
+- [ ] CSAT ≥ 8/10.
+
+---
+
+## 8. مقاييس Pilot في Operating Board
+
+| Metric | Target |
+|--------|-------:|
+| Pilot delivered ≤ 48h | 100% |
+| Drafts approved (من 10) | ≥3 |
+| Replies received | ≥1 |
+| Meetings booked | ≥1 |
+| Risks blocked | ≥1 |
+| Upsell offered | 100% |
+| Upsell accepted | ≥30% |
+| CSAT | ≥8/10 |
+
+---
+
+## 9. القرار النهائي
+
+```
+Pilot ليس "محاولة بيع".
+Pilot هو "أول إثبات أن Dealix يعمل لشركتك".
+لو سُلّم في 48 ساعة + ≥3 رسائل اعتمدت + 1 رد + 1 اجتماع =
+هذا Growth OS subscription بأعلى احتمال.
+```
diff --git a/dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md b/dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md
new file mode 100644
index 00000000..0a29088b
--- /dev/null
+++ b/dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md
@@ -0,0 +1,206 @@
+# Paid Beta Operating Playbook
+
+> **القاعدة:** الجاهزية التقنية لا تعني دخل. هذا الـ playbook يحوّل GO_PRIVATE_BETA إلى أول 499 ريال خلال 7 أيام.
+
+---
+
+## 1. الحالة الحالية
+
+```
+✅ Tests: 949 passed, 2 skipped
+✅ CI green
+✅ Service Tower + Service Excellence + Targeting OS + Customer Ops جاهزة
+✅ Positioning Lock مفعّل
+✅ Landing pages متوافقة مع POSITIONING_LOCK
+🟡 Staging: ينتظر النشر الفعلي
+🟡 First payment: ينتظر أول عميل
+```
+
+**الحالة:** `GO_PRIVATE_BETA` محلياً. الانتقال لـ `PAID_BETA_READY` يحتاج Staging شغّال + أول Pilot مدفوع.
+
+---
+
+## 2. الانتقال من Private Beta إلى Paid Beta
+
+### Gate الانتقال (لا تتجاوزه)
+
+```text
+✅ Staging /health = 200
+✅ Service catalog يعرض 4+ خدمات
+✅ landing/private-beta.html فيه 499 SAR + CTA
+✅ no_secrets scan نظيف
+✅ live_sends_disabled = true
+✅ Moyasar invoice/payment-link manual flow جاهز
+✅ أول 20 prospect معرّفون في Operating Board
+```
+
+### Smoke Commands
+
+```bash
+export STAGING_BASE_URL="https://YOUR-STAGING-URL"
+python scripts/smoke_staging.py --base-url "$STAGING_BASE_URL"
+python scripts/launch_readiness_check.py --staging-url "$STAGING_BASE_URL"
+python scripts/paid_beta_daily_scorecard.py --as-of today
+```
+
+المطلوب: `PAID_BETA_READY`. لو NO-GO → أصلح السبب قبل أي بيع.
+
+---
+
+## 3. خطة 7 أيام للوصول للدخل الأول
+
+### يوم 1 — Staging + Outreach
+- نشر staging على Railway.
+- تشغيل smoke + readiness checks.
+- إرسال 10 رسائل (5 وكالات + 5 شركات).
+- 1 منشور LinkedIn (founder voice).
+
+**الهدف:** 2 ردود + 1 ديمو محجوز.
+
+### يوم 2 — Demos
+- إرسال 10 رسائل أخرى.
+- إجراء أول 1-2 ديمو.
+- بدء أول Free Diagnostic لأي عميل اهتم.
+
+**الهدف:** 1 Free Diagnostic موعود.
+
+### يوم 3 — Diagnostic Delivery
+- تسليم أول Free Diagnostic خلال 24 ساعة.
+- 5 follow-ups.
+- إرسال 5 رسائل جديدة.
+
+**الهدف:** 1 Pilot Offer.
+
+### يوم 4 — First Pilot Sale
+- محادثة Pilot 499 مع المهتم.
+- إنشاء Moyasar invoice manual.
+- إرسال payment-link-message.
+
+**الهدف:** 1 invoice paid أو commitment مكتوب.
+
+### يوم 5 — Pilot Delivery Day 1
+- استلام intake من العميل.
+- تشغيل First 10 Opportunities Sprint workflow.
+- 10 opportunities + 10 رسائل عربية.
+
+**الهدف:** Approval Pack مرسل للعميل.
+
+### يوم 6 — Pilot Delivery Day 2
+- متابعة الموافقات.
+- تشغيل follow-up sequence.
+- أول 1-2 رد إيجابي.
+
+**الهدف:** اعتماد ≥3 رسائل + Proof Pack v1.
+
+### يوم 7 — Proof + Upsell
+- تسليم Proof Pack.
+- جلسة مراجعة 30 دقيقة.
+- اقتراح ترقية لـ Growth OS Pilot.
+
+**الهدف:** Case study أو Pilot ثانٍ.
+
+---
+
+## 4. أهداف الأسبوع
+
+| Metric | Target |
+|--------|-------:|
+| Messages sent | 50–70 |
+| Positive replies | 5–10 |
+| Demos booked | 3–5 |
+| Pilots offered | 2–3 |
+| Payments requested | 1–2 |
+| Payments received | 1+ |
+| Proof packs delivered | 1+ |
+
+---
+
+## 5. القواعد التشغيلية اليومية (لا تتنازل عنها)
+
+1. **لا live WhatsApp send** بدون env flag + اعتماد بشري.
+2. **لا live Gmail send** بدون env flag + اعتماد بشري.
+3. **لا Calendar insert** بدون اعتماد.
+4. **لا Moyasar charge** من API — invoice/payment-link manual فقط.
+5. **لا scraping LinkedIn** ولا auto-DM — Lead Gen Forms + manual فقط.
+6. **لا cold WhatsApp** بدون opt-in — PDPL hard-block.
+7. **كل رسالة** تمر `safety_eval` + `saudi_tone_eval` قبل الإرسال.
+8. **كل فعل** يُسجّل في Action Ledger.
+
+---
+
+## 6. Daily Cadence
+
+### الصباح (60 دقيقة)
+- شغّل `paid_beta_daily_scorecard.py`.
+- راجع الـ Operating Board.
+- اعتمد drafts اليوم (10–15 دقيقة).
+- 5 follow-ups.
+
+### الظهر (90 دقيقة)
+- 1–2 ديمو.
+- 10 رسائل جديدة (segments متنوعة).
+
+### العصر (60 دقيقة)
+- تسليم deliverable لعميل واحد.
+- إجابة support tickets (إن وجد).
+
+### آخر اليوم (30 دقيقة)
+- تحديث Operating Board.
+- تشغيل scorecard مرة أخرى.
+- خطة الغد.
+
+---
+
+## 7. ما لا تضيفه هذا الأسبوع
+
+- لا ميزات تقنية جديدة.
+- لا layers معمارية.
+- لا modules جديدة.
+- لا بريق landing.
+
+**التركيز كله:** عميل واحد يدفع 499 ريال.
+
+---
+
+## 8. شروط الانتقال إلى Public Launch
+
+لا انتقال قبل:
+```
+5–10 pilots
+2+ paid customers
+0 unsafe sends
+weekly proof packs delivered
+support flow يعمل
+funnel واضح من lead → demo → pilot → paid
+14 يوم staging stable
+billing live (Moyasar API webhook)
+terms + privacy + DPA
+```
+
+---
+
+## 9. Endpoints المهمة في Paid Beta
+
+```
+GET /api/v1/launch/private-beta/offer
+POST /api/v1/launch/go-no-go
+GET /api/v1/launch/scorecard/demo
+GET /api/v1/operator/bundles
+POST /api/v1/operator/chat/message
+POST /api/v1/customer-ops/onboarding/checklist
+POST /api/v1/customer-ops/connectors/summary
+POST /api/v1/revenue-launch/payment/invoice-instructions
+POST /api/v1/revenue-launch/proof-pack/template
+GET /api/v1/service-excellence/review/all
+```
+
+---
+
+## 10. القرار النهائي
+
+```
+لا تنتظر "كمال المنتج". المنتج كامل تقنياً.
+أنت تنتظر "أول إيراد".
+الإيراد يأتي من 50 رسالة يدوية + 5 ديمو + 1 invoice.
+ابدأ.
+```
diff --git a/dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md b/dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md
new file mode 100644
index 00000000..73030a83
--- /dev/null
+++ b/dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md
@@ -0,0 +1,183 @@
+# Private Beta Operating Board
+
+> **القاعدة:** كل prospect يدخل هذا الـ Board. كل خطوة تُسجّل. كل تأخير يولّد action item. هذا هو الـ source of truth للأسبوع.
+
+---
+
+## 1. أين يعيش هذا الـ Board؟
+
+- **Primary:** Google Sheet خاص بك (لا تشاركه بصلاحيات edit مع أحد).
+- **Backup:** نسخة في `pilots/operating_board.csv` (gitignored) في المستودع.
+- **عدم التشارك:** هذا Sheet يحتوي PII لأشخاص لم يوافقوا — لا تشاركه.
+
+---
+
+## 2. الأعمدة (15 عمود)
+
+| # | Column | النوع | شرح | مثال |
+|---|--------|------|------|------|
+| 1 | `company` | text | اسم الشركة الرسمي | شركة الأثاث المتقدم |
+| 2 | `person` | text | اسم صاحب القرار | أحمد العتيبي |
+| 3 | `segment` | enum | `agency` / `b2b_company` / `partnership` | b2b_company |
+| 4 | `source` | enum | `linkedin_lead_form` / `referral` / `inbound` / `event` / `personal_network` | personal_network |
+| 5 | `channel` | enum | `whatsapp` (opt-in) / `email` / `linkedin_dm_manual` / `call` | linkedin_dm_manual |
+| 6 | `message_sent` | date | تاريخ إرسال أول رسالة | 2026-05-01 |
+| 7 | `reply_status` | enum | `none` / `positive` / `objection` / `not_now` / `bounce` | positive |
+| 8 | `demo_booked` | date \| null | تاريخ الديمو لو حُجز | 2026-05-03 |
+| 9 | `diagnostic_sent` | date \| null | تاريخ تسليم Free Diagnostic | 2026-05-04 |
+| 10 | `pilot_offered` | date \| null | تاريخ عرض Pilot 499 | 2026-05-05 |
+| 11 | `price` | int | السعر المعروض (499 / 1500 / 2999) | 499 |
+| 12 | `paid` | enum | `no` / `pending_invoice` / `paid` / `case_study` | pending_invoice |
+| 13 | `proof_pack_sent` | date \| null | تاريخ تسليم Proof Pack | null |
+| 14 | `next_step` | text | الإجراء التالي وتاريخه | 2026-05-06: follow-up #1 |
+| 15 | `notes` | text | ملاحظات (بدون PII حساسة) | اهتم بـ partnerships في الرياض |
+
+---
+
+## 3. Status Flow
+
+```
+prospect_added
+ → message_sent
+ → reply_status (none | positive | objection | not_now | bounce)
+ → demo_booked
+ → diagnostic_sent (T+24)
+ → pilot_offered (T+48)
+ → paid (or case_study)
+ → proof_pack_sent (T+7 من بدء Pilot)
+ → renewal_or_upsell
+```
+
+كل عميل يجب أن يكون في حالة واحدة من هذه المراحل في كل لحظة.
+
+---
+
+## 4. أهداف الأسبوع (الصف الأول من الـ Board)
+
+| Metric | Target | Tracking |
+|--------|-------:|----------|
+| Prospects added | 50–70 | عداد عمود `company` |
+| Messages sent | 50–70 | عدد التواريخ في `message_sent` |
+| Positive replies | 5–10 | `reply_status = positive` |
+| Demos booked | 3–5 | عدد التواريخ في `demo_booked` |
+| Diagnostics sent | 2–4 | عدد التواريخ في `diagnostic_sent` |
+| Pilots offered | 2–3 | عدد التواريخ في `pilot_offered` |
+| Paid | 1+ | `paid = paid` |
+| Proof packs sent | 1+ | عدد التواريخ في `proof_pack_sent` |
+
+---
+
+## 5. ICP Distribution (في 50–70 prospect)
+
+```
+Agencies (B2B marketing agencies) 20%
+Construction & home services 20%
+Clinics + dental + aesthetic 15%
+Logistics + last-mile 15%
+F&B (restaurants + cloud kitchens) 10%
+Retail (offline + ecom) 10%
+EdTech / SaaS B2B 10%
+```
+
+اضبط النسبة حسب القطاعات التي يخدمها العميل المثالي.
+
+---
+
+## 6. Cadence لكل prospect
+
+| اليوم | الإجراء |
+|------|--------|
+| Day 0 | إرسال الرسالة الأولى + تسجيلها في الـ Board |
+| Day 1 | تحقق من reply_status + Operating Board update |
+| Day 2 | متابعة #1 (لو لا رد) — قالب Follow-up #1 |
+| Day 4 | متابعة #2 (لو لا رد) — تحويل قناة لو منطقي |
+| Day 7 | قرار keep / drop / nurture |
+| Day 14 | nurture: رسالة قيمة (مثل Diagnostic مجاني للناس البطيئين) |
+
+---
+
+## 7. Follow-up Templates (3 موجات)
+
+### Follow-up #1 (يوم 2)
+> أنت اللي ذكرت . حضّرت لك مثال محدد لشركتك (3 فرص + رسالة جاهزة بالعربي + مخاطرة موجودة الآن). أرسله لك بعد ردك. ما يأخذ منك ≥3 دقائق.
+
+### Follow-up #2 (يوم 4 — تحويل قناة لو منطقي)
+> سمعت أن . هذا أفضل وقت تجرب نموذج بسيط: 10 فرص + رسائل خلال 48 ساعة، 499 ريال، يبدأ غداً. لو ما عجبك في 7 أيام، تستردّ المبلغ.
+
+### Follow-up #3 (يوم 7 — قرار)
+> سأوقف المحاولات بعد هذه الرسالة. لو هذا توقيت غير مناسب، حدد لي شهر تجارب أخرى — وأذكّرك. مكتب مفتوح دائماً.
+
+كل القوالب تمر `safety_eval` + `saudi_tone_eval` قبل الإرسال.
+
+---
+
+## 8. Daily Routine لإدارة الـ Board
+
+### الصباح (15 دقيقة)
+- افتح الـ Sheet.
+- صفّ حسب `next_step` (date asc).
+- نفّذ الـ next_step لكل prospect وصلت تاريخه.
+- شغّل `paid_beta_daily_scorecard.py`.
+
+### الظهر (15 دقيقة)
+- أضف prospects الجدد (5–10 يومياً).
+- خصّص الرسالة لكل واحد (اسم + قطاع + city + why_now).
+- اعتمد drafts.
+
+### آخر اليوم (10 دقائق)
+- حدّث `reply_status` للذين ردّوا.
+- حدّث `next_step` لكل prospect نشط.
+- شغّل `paid_beta_daily_scorecard.py --json` واحفظه يومياً.
+
+---
+
+## 9. Privacy & PDPL
+
+- **لا تشارك** هذا الـ Sheet بصلاحيات edit مع أحد.
+- **لا تخزّن** أرقام واتساب لأشخاص لم يوافقوا opt-in.
+- **لا تنسخ** الـ Sheet إلى أدوات خارجية بدون اتفاقية data processing.
+- **احذف** البيانات بعد 90 يوم لمن لم يرد ولم يطلب nurture.
+- **سجّل** كل export في Action Ledger.
+
+---
+
+## 10. مثال صف كامل
+
+```
+| company | شركة الأثاث المتقدم |
+| person | أحمد العتيبي |
+| segment | b2b_company |
+| source | personal_network |
+| channel | linkedin_dm_manual |
+| message_sent | 2026-05-01 |
+| reply_status | positive |
+| demo_booked | 2026-05-03 |
+| diagnostic_sent| 2026-05-04 |
+| pilot_offered | 2026-05-05 |
+| price | 499 |
+| paid | pending_invoice |
+| proof_pack_sent| null |
+| next_step | 2026-05-06: متابعة دفع invoice |
+| notes | اهتم بـ partnerships في الرياض |
+```
+
+---
+
+## 11. Sheet template (CSV header للنسخ)
+
+```csv
+company,person,segment,source,channel,message_sent,reply_status,demo_booked,diagnostic_sent,pilot_offered,price,paid,proof_pack_sent,next_step,notes
+```
+
+ضع هذا الصف كـ header في Google Sheet جديد. ابدأ.
+
+---
+
+## 12. القرار
+
+```
+الـ Board ليس "نظاماً".
+الـ Board هو "الذاكرة العاملة" لأسبوعك.
+بدون الـ Board: prospects ينسون، follow-ups تضيع، payments تتأخر.
+مع الـ Board: 50 prospect → 5 ردود → 3 ديمو → 1 paid.
+```
diff --git a/dealix/landing/private-beta.html b/dealix/landing/private-beta.html
index 89e2d4f6..e872746b 100644
--- a/dealix/landing/private-beta.html
+++ b/dealix/landing/private-beta.html
@@ -139,18 +139,69 @@
- Private Beta — متاح اليوم
- مدير نمو عربي للشركات السعودية
+ Private Beta — Pilot 499 ريال يبدأ اليوم
+ 10 فرص B2B + رسائل عربية + متابعة خلال 48 ساعة
- Dealix يعطيك 10 فرص B2B خلال 10 دقائق، يكتب الرسائل بالعربي،
- ويطلع لك Proof Pack — وأنت توافق قبل أي تواصل.
+ Dealix هو Saudi Revenue Execution OS — مش CRM، ولا WhatsApp bot، ولا lead scraper.
+
+ Pilot 7 أيام بـ 499 ريال فقط.
+ تسليم خلال 48 ساعة. لا إرسال خارجي بدون موافقتك.
+
+ احجز Pilot 499 الآن
+ شاهد ماذا تحصل
+
+ أو ضمان: لو ما عجبك خلال 7 أيام، تستردّ كامل المبلغ — أو نحوّله Case Study مجاني.
- احجز Pilot الآن
- شاهد ديمو 12 دقيقة
-
-
+
+
+ عرض اليوم — Pilot 499 ريال
+
+
+
First 10 Opportunities Sprint
+
499 ر.س
+
يبدأ خلال 24 ساعة
+
+ - 10 فرص B2B بأسماء حقيقية
+ - 10 رسائل عربية جاهزة
+ - خطة متابعة 7 أيام
+ - Proof Pack نهائي
+ - تسليم ≤ 48 ساعة
+
+
ابدأ Pilot الآن
+
+
+
Free Diagnostic
+
مجاني
+
تسليم خلال 24 ساعة
+
+ - 3 فرص محددة
+ - 1 رسالة عربية جاهزة
+ - 1 مخاطرة موجودة الآن
+ - 1 توصية خدمة
+
+
جرّب مجاناً
+
+
+
Growth OS Monthly
+
2,999 ر.س/شهر
+
اشتراك مستمر
+
+ - 30+ فرصة شهرياً
+ - متابعة + Reply classifier
+ - Proof Pack أسبوعي
+ - Weekly check-in
+
+
يُقدَّم بعد Pilot ناجح فقط.
+
+
+
+ الدفع عبر Moyasar (invoice يدوي). لا API charge. لا اشتراك تلقائي.
+
+
+
+
وعد المنتج
خلال 7 أيام، نطلع لك:
-
- الأسعار
-
-
-
Pilot 7 أيام
-
499 ريال
-
أو مجاني مقابل case study
-
-
-
Paid Pilot 30 يوم
-
1,500–3,000 ريال
-
إعداد + Pilot موسّع
-
-
-
Growth OS شهري
-
2,999 ريال
-
اشتراك مستمر
-
-
-
-
-
- جاهز نبدأ؟
+
+ جاهز نبدأ؟ — Pilot 499 ريال يبدأ خلال 24 ساعة
- Pilot يبدأ يوم الأحد التالي.
- أرسل لي اسمك + اسم شركتك + قطاعك + مدينتك،
- وأرتّب لك ديمو 12 دقيقة هذا الأسبوع.
+ أرسل لي: اسمك + اسم شركتك + قطاعك + مدينتك + عميلك المثالي.
+ خلال 24 ساعة يصلك Free Diagnostic. خلال 48 ساعة Pilot كامل (10 فرص + 10 رسائل + متابعة).
- احجز Pilot الآن
+
+ ضمان: لو ما عجبك خلال 7 أيام، تستردّ كامل المبلغ.
+
+ احجز Pilot 499 الآن
+ جرّب Free Diagnostic
diff --git a/dealix/scripts/paid_beta_daily_scorecard.py b/dealix/scripts/paid_beta_daily_scorecard.py
new file mode 100644
index 00000000..94c19189
--- /dev/null
+++ b/dealix/scripts/paid_beta_daily_scorecard.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python3
+"""Paid Beta Daily Scorecard — تتبّع التقدّم اليومي نحو أول إيراد.
+
+كل يوم في Paid Beta، شغّل:
+
+ python scripts/paid_beta_daily_scorecard.py \\
+ --messages 25 --replies 4 --demos 2 --pilots 1 --payments 0 --proof-packs 0
+
+أو بصيغة JSON للأتمتة:
+
+ python scripts/paid_beta_daily_scorecard.py \\
+ --messages 25 --replies 4 --demos 2 --pilots 1 --payments 1 --proof-packs 0 --json
+
+الهدف خلال 7 أيام:
+ 70 تواصل يدوي / 15 رد / 7 ديمو / 3 pilots / 1–2 paid / 1 Proof Pack على الأقل.
+"""
+
+from __future__ import annotations
+
+import argparse
+import json
+import sys
+from dataclasses import asdict, dataclass
+from datetime import date
+
+
+# ----- Targets -----
+
+WEEKLY_TARGETS = {
+ "messages": {"min": 50, "stretch": 70},
+ "replies": {"min": 5, "stretch": 15},
+ "demos": {"min": 3, "stretch": 7},
+ "pilots": {"min": 2, "stretch": 3},
+ "payments": {"min": 1, "stretch": 2},
+ "proof_packs": {"min": 1, "stretch": 1},
+}
+
+DAILY_TARGETS = {
+ # ÷ 7 (مدوّر للأعلى) لأي metric
+ "messages": 10,
+ "replies": 1,
+ "demos": 1,
+ "pilots": 0, # ≥1 خلال الأسبوع
+ "payments": 0, # ≥1 خلال الأسبوع
+ "proof_packs": 0, # ≥1 خلال الأسبوع
+}
+
+
+# ----- Computation -----
+
+@dataclass
+class Scorecard:
+ as_of: str
+ messages: int
+ replies: int
+ demos: int
+ pilots: int
+ payments: int
+ proof_packs: int
+ reply_rate: float
+ demo_rate: float
+ pilot_rate: float
+ payment_rate: float
+ daily_verdict: str
+ weekly_verdict: str
+ next_actions: list[str]
+
+
+def _safe_div(a: int, b: int) -> float:
+ return round(a / b, 3) if b > 0 else 0.0
+
+
+def _daily_verdict(metrics: dict[str, int]) -> str:
+ """Compare today's metrics to daily targets."""
+ misses = []
+ for key, target in DAILY_TARGETS.items():
+ if target == 0:
+ continue
+ if metrics[key] < target:
+ misses.append(f"{key}: {metrics[key]}/{target}")
+ if not misses:
+ return "ON_TRACK"
+ if len(misses) == 1:
+ return f"BEHIND on {misses[0]}"
+ return f"OFF_TRACK: {', '.join(misses)}"
+
+
+def _weekly_verdict(metrics: dict[str, int]) -> str:
+ """Compare cumulative-week metrics to weekly targets (assumes the input is week-to-date totals)."""
+ blockers = []
+ misses = []
+ for key, t in WEEKLY_TARGETS.items():
+ v = metrics[key]
+ if v < t["min"]:
+ blockers.append(f"{key} {v}/{t['min']}")
+ elif v < t["stretch"]:
+ misses.append(f"{key} {v}/{t['stretch']}")
+ if not blockers and not misses:
+ return "WEEKLY_TARGETS_HIT"
+ if blockers:
+ return "BLOCKERS: " + ", ".join(blockers)
+ return "STRETCH_PENDING: " + ", ".join(misses)
+
+
+def _next_actions(metrics: dict[str, int]) -> list[str]:
+ actions: list[str] = []
+
+ if metrics["messages"] < DAILY_TARGETS["messages"]:
+ deficit = DAILY_TARGETS["messages"] - metrics["messages"]
+ actions.append(
+ f"أرسل {deficit} رسالة إضافية اليوم (LinkedIn/Email/WhatsApp opt-in فقط)."
+ )
+
+ if metrics["messages"] >= 5 and metrics["replies"] == 0:
+ actions.append(
+ "0 ردود مع >5 رسائل — راجع نبرة الرسالة وعدّلها (saudi_tone_eval)."
+ )
+
+ if metrics["replies"] >= 2 and metrics["demos"] == 0:
+ actions.append(
+ "ردود إيجابية بدون ديمو — احجز ديمو 12 دقيقة لكل رد إيجابي اليوم."
+ )
+
+ if metrics["demos"] >= 2 and metrics["pilots"] == 0:
+ actions.append(
+ "ديمو ≥2 بدون عرض Pilot — أرسل عرض Pilot 499 + Free Diagnostic لكل ديمو."
+ )
+
+ if metrics["pilots"] >= 1 and metrics["payments"] == 0:
+ actions.append(
+ "Pilot معروض بدون دفع — تابع Moyasar invoice manual + رسالة متابعة دفع."
+ )
+
+ if metrics["payments"] >= 1 and metrics["proof_packs"] == 0:
+ actions.append(
+ "أول دفعة وصلت — ابدأ Pilot delivery + أعد Proof Pack v1 خلال 48 ساعة."
+ )
+
+ if not actions:
+ actions.append(
+ "اليوم ON_TRACK. حافظ على الإيقاع: 10 رسائل + 5 follow-ups + 1 ديمو."
+ )
+
+ return actions
+
+
+def build_scorecard(
+ messages: int,
+ replies: int,
+ demos: int,
+ pilots: int,
+ payments: int,
+ proof_packs: int,
+ as_of: str | None = None,
+) -> Scorecard:
+ metrics = {
+ "messages": messages,
+ "replies": replies,
+ "demos": demos,
+ "pilots": pilots,
+ "payments": payments,
+ "proof_packs": proof_packs,
+ }
+ return Scorecard(
+ as_of=as_of or date.today().isoformat(),
+ messages=messages,
+ replies=replies,
+ demos=demos,
+ pilots=pilots,
+ payments=payments,
+ proof_packs=proof_packs,
+ reply_rate=_safe_div(replies, messages),
+ demo_rate=_safe_div(demos, replies),
+ pilot_rate=_safe_div(pilots, demos),
+ payment_rate=_safe_div(payments, pilots),
+ daily_verdict=_daily_verdict(metrics),
+ weekly_verdict=_weekly_verdict(metrics),
+ next_actions=_next_actions(metrics),
+ )
+
+
+# ----- Rendering -----
+
+def render_text(card: Scorecard) -> str:
+ lines = [
+ "════════════════════════════════════════════════",
+ f" Paid Beta Daily Scorecard — {card.as_of}",
+ "════════════════════════════════════════════════",
+ "",
+ "اليوم:",
+ f" 📨 رسائل أُرسلت: {card.messages:>3} (يومي ≥10)",
+ f" 💬 ردود إيجابية: {card.replies:>3} (يومي ≥1)",
+ f" 📅 ديمو محجوز: {card.demos:>3} (يومي ≥1)",
+ f" 🚀 Pilots معروضة: {card.pilots:>3} (أسبوعي ≥2)",
+ f" 💳 دفعات وصلت: {card.payments:>3} (أسبوعي ≥1)",
+ f" 📦 Proof Packs مرسلة: {card.proof_packs:>3} (أسبوعي ≥1)",
+ "",
+ "Conversion Rates:",
+ f" reply_rate = {card.reply_rate:.1%}",
+ f" demo_rate = {card.demo_rate:.1%} (replies → demos)",
+ f" pilot_rate = {card.pilot_rate:.1%} (demos → pilots)",
+ f" payment_rate = {card.payment_rate:.1%} (pilots → paid)",
+ "",
+ f"Daily Verdict: {card.daily_verdict}",
+ f"Weekly Verdict: {card.weekly_verdict}",
+ "",
+ "Next Actions:",
+ ]
+ for i, action in enumerate(card.next_actions, 1):
+ lines.append(f" {i}. {action}")
+ lines.extend([
+ "",
+ "════════════════════════════════════════════════",
+ "Targets: 50–70 messages / 5–15 replies / 3–7 demos /",
+ " 2–3 pilots / 1–2 paid / 1+ proof pack الأسبوع.",
+ "════════════════════════════════════════════════",
+ ])
+ return "\n".join(lines)
+
+
+def render_json(card: Scorecard) -> str:
+ return json.dumps(asdict(card), ensure_ascii=False, indent=2)
+
+
+# ----- CLI -----
+
+def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
+ p = argparse.ArgumentParser(
+ description="Paid Beta daily scorecard — track manual outreach progress.",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog=(
+ "Examples:\n"
+ " python scripts/paid_beta_daily_scorecard.py "
+ "--messages 25 --replies 4 --demos 2 --pilots 1 --payments 0 --proof-packs 0\n"
+ " python scripts/paid_beta_daily_scorecard.py "
+ "--messages 25 --replies 4 --demos 2 --pilots 1 --payments 1 --proof-packs 0 --json"
+ ),
+ )
+ p.add_argument("--messages", type=int, default=0, help="رسائل أُرسلت")
+ p.add_argument("--replies", type=int, default=0, help="ردود إيجابية")
+ p.add_argument("--demos", type=int, default=0, help="ديمو محجوز")
+ p.add_argument("--pilots", type=int, default=0, help="Pilots معروضة")
+ p.add_argument("--payments", type=int, default=0, help="دفعات وصلت")
+ p.add_argument("--proof-packs", dest="proof_packs", type=int, default=0,
+ help="Proof Packs مُسلَّمة")
+ p.add_argument("--as-of", type=str, default=None,
+ help="تاريخ (YYYY-MM-DD أو 'today')")
+ p.add_argument("--json", action="store_true", help="إخراج JSON")
+ return p.parse_args(argv)
+
+
+def main(argv: list[str] | None = None) -> int:
+ args = parse_args(argv)
+ as_of = None if (args.as_of in (None, "today")) else args.as_of
+ card = build_scorecard(
+ messages=args.messages,
+ replies=args.replies,
+ demos=args.demos,
+ pilots=args.pilots,
+ payments=args.payments,
+ proof_packs=args.proof_packs,
+ as_of=as_of,
+ )
+ output = render_json(card) if args.json else render_text(card)
+ try:
+ sys.stdout.reconfigure(encoding="utf-8")
+ except (AttributeError, OSError):
+ pass
+ print(output)
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/dealix/tests/unit/test_paid_beta_scorecard.py b/dealix/tests/unit/test_paid_beta_scorecard.py
new file mode 100644
index 00000000..d936e934
--- /dev/null
+++ b/dealix/tests/unit/test_paid_beta_scorecard.py
@@ -0,0 +1,125 @@
+"""Unit tests for the Paid Beta Daily Scorecard script."""
+
+from __future__ import annotations
+
+import json
+import sys
+from pathlib import Path
+
+REPO_ROOT = Path(__file__).resolve().parents[2]
+SCRIPTS_DIR = REPO_ROOT / "scripts"
+if str(SCRIPTS_DIR) not in sys.path:
+ sys.path.insert(0, str(SCRIPTS_DIR))
+
+import paid_beta_daily_scorecard as pbds # noqa: E402
+
+
+# ----- core scorecard logic -----
+
+def test_zero_input_yields_off_track():
+ card = pbds.build_scorecard(0, 0, 0, 0, 0, 0, as_of="2026-05-01")
+ assert card.messages == 0
+ assert card.reply_rate == 0.0
+ # 0 messages, 0 replies, 0 demos → daily target on messages is breached.
+ assert "OFF_TRACK" in card.daily_verdict or "BEHIND" in card.daily_verdict
+ assert any("رسالة" in a or "messages" in a.lower() for a in card.next_actions)
+
+
+def test_full_day_on_track():
+ card = pbds.build_scorecard(10, 1, 1, 0, 0, 0, as_of="2026-05-01")
+ assert card.daily_verdict == "ON_TRACK"
+ # Weekly is still in early days; expect blockers but daily is fine.
+ assert "BLOCKERS" in card.weekly_verdict
+
+
+def test_high_message_zero_reply_triggers_tone_action():
+ card = pbds.build_scorecard(20, 0, 0, 0, 0, 0)
+ assert any("نبرة" in a or "tone" in a.lower() for a in card.next_actions)
+
+
+def test_payment_received_advances_proof_pack_action():
+ card = pbds.build_scorecard(20, 4, 2, 1, 1, 0)
+ assert any("Proof Pack" in a for a in card.next_actions)
+
+
+def test_weekly_targets_hit_when_full_week():
+ card = pbds.build_scorecard(70, 15, 7, 3, 2, 1)
+ assert card.weekly_verdict == "WEEKLY_TARGETS_HIT"
+
+
+def test_conversion_rates_computed():
+ card = pbds.build_scorecard(25, 5, 2, 1, 1, 0)
+ assert card.reply_rate == 0.2
+ assert card.demo_rate == 0.4
+ assert card.pilot_rate == 0.5
+ assert card.payment_rate == 1.0
+
+
+# ----- rendering -----
+
+def test_render_text_contains_arabic_labels():
+ card = pbds.build_scorecard(25, 4, 2, 1, 0, 0)
+ text = pbds.render_text(card)
+ assert "Paid Beta Daily Scorecard" in text
+ assert "رسائل أُرسلت" in text
+ assert "Daily Verdict" in text
+ assert "Weekly Verdict" in text
+ assert "Next Actions" in text
+
+
+def test_render_json_is_valid_json():
+ card = pbds.build_scorecard(25, 4, 2, 1, 0, 0, as_of="2026-05-01")
+ output = pbds.render_json(card)
+ parsed = json.loads(output)
+ assert parsed["messages"] == 25
+ assert parsed["as_of"] == "2026-05-01"
+ assert "next_actions" in parsed
+ assert isinstance(parsed["next_actions"], list)
+
+
+# ----- CLI -----
+
+def test_cli_main_text_mode(capsys):
+ rc = pbds.main([
+ "--messages", "25", "--replies", "4",
+ "--demos", "2", "--pilots", "1",
+ "--payments", "0", "--proof-packs", "0",
+ ])
+ assert rc == 0
+ captured = capsys.readouterr()
+ assert "Paid Beta Daily Scorecard" in captured.out
+ assert "25" in captured.out
+
+
+def test_cli_main_json_mode(capsys):
+ rc = pbds.main([
+ "--messages", "25", "--replies", "4",
+ "--demos", "2", "--pilots", "1",
+ "--payments", "1", "--proof-packs", "0",
+ "--json",
+ ])
+ assert rc == 0
+ captured = capsys.readouterr()
+ payload = json.loads(captured.out)
+ assert payload["messages"] == 25
+ assert payload["payments"] == 1
+ assert payload["weekly_verdict"]
+
+
+def test_cli_as_of_today(capsys):
+ rc = pbds.main(["--messages", "10", "--as-of", "today"])
+ assert rc == 0
+ captured = capsys.readouterr()
+ # 'today' should resolve to a real date string in the output (YYYY-MM-DD).
+ assert "20" in captured.out # any year starts with "20" in our era
+
+
+def test_cli_as_of_explicit(capsys):
+ rc = pbds.main([
+ "--messages", "10", "--as-of", "2026-04-30",
+ "--json",
+ ])
+ assert rc == 0
+ captured = capsys.readouterr()
+ payload = json.loads(captured.out)
+ assert payload["as_of"] == "2026-04-30"