diff --git a/salesflow-saas/backend/dealix_marketing_os/__init__.py b/salesflow-saas/backend/dealix_marketing_os/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/dealix_marketing_os/cli/__init__.py b/salesflow-saas/backend/dealix_marketing_os/cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/dealix_marketing_os/cli/generate_daily_marketing_pack.py b/salesflow-saas/backend/dealix_marketing_os/cli/generate_daily_marketing_pack.py new file mode 100644 index 00000000..7146fc48 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/cli/generate_daily_marketing_pack.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +"""Generate daily marketing pack — dry-run only.""" +import sys, os, json +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) +from dealix_marketing_os.pipelines.daily_marketing_pack_pipeline import generate_daily_marketing_pack + +def main(): + day = int(sys.argv[1]) if len(sys.argv) > 1 else 1 + pack = generate_daily_marketing_pack(day_number=day) + print(f"=== DEALIX DAILY MARKETING PACK — Day {day} ===") + print(f"Strategy: {pack['strategy']['strategy_summary']}") + print(f"Theme: {pack['content']['theme']}") + print(f"LinkedIn: {pack['content']['linkedin']['post'][:60]}...") + print(f"X: {pack['content']['x']['post'][:60]}...") + print(f"IG Story: {pack['content']['instagram_story']['text'][:60]}...") + print(f"WA Status: {pack['content']['whatsapp_status']['text'][:60]}...") + print(f"Partner: {pack['partner_assets']['agency_pitch'][:60]}...") + print(f"Auto-post: {pack['no_auto_post']} (manual only)") + print(f"Auto-send: {pack['no_auto_send']} (manual only)") + +if __name__ == "__main__": + main() diff --git a/salesflow-saas/backend/dealix_marketing_os/config/__init__.py b/salesflow-saas/backend/dealix_marketing_os/config/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/dealix_marketing_os/config/content_pillars.yaml b/salesflow-saas/backend/dealix_marketing_os/config/content_pillars.yaml new file mode 100644 index 00000000..09938ca0 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/config/content_pillars.yaml @@ -0,0 +1,40 @@ +pillars: + - id: lost_leads + name_ar: "ضياع الاستفسارات بعد الإعلان" + hook: "كل حملة تجيب leads ثم تضيع" + - id: whatsapp_followup + name_ar: "متابعة واتساب" + hook: "واتسابك مليان استفسارات بدون متابعة" + - id: speed_to_lead + name_ar: "سرعة الرد" + hook: "أول 5 دقائق هي اللي تحدد" + - id: agency_addon + name_ar: "خدمة جديدة للوكالات" + hook: "أضف خدمة متابعة leads لعملائك" + - id: partner_earning + name_ar: "اربح كشريك" + hook: "اربح من أول اشتراك مدفوع مؤهل" + - id: arabic_first + name_ar: "عربي أولاً" + hook: "مبني للسوق السعودي — مو ترجمة" + - id: build_in_public + name_ar: "بناء أمام الجميع" + hook: "رحلة بناء Dealix" + - id: revenue_ops + name_ar: "تشغيل الإيراد" + hook: "من lead إلى دفع — مسار كامل" + - id: customer_delivery + name_ar: "خدمة العميل" + hook: "مو بس نبيع — نشغّل" + - id: proof_and_safety + name_ar: "إثبات وأمان" + hook: "لا spam. لا scraping. موافقة بشرية." + +formats: + linkedin: {type: "text", max_words: 200, cta: true, arabic: true} + x: {type: "text", max_words: 50, cta: false, arabic: true} + instagram_story: {type: "visual+text", max_words: 30, cta: true} + instagram_carousel: {type: "slides", slides: "5-7", cta: true} + reel_script: {type: "video", duration_sec: "30-60", hook_first: true} + whatsapp_status: {type: "text", max_words: 25, informal: true} + email_newsletter: {type: "long", max_words: 500, cta: true} diff --git a/salesflow-saas/backend/dealix_marketing_os/config/seo_targets.yaml b/salesflow-saas/backend/dealix_marketing_os/config/seo_targets.yaml new file mode 100644 index 00000000..66490d16 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/config/seo_targets.yaml @@ -0,0 +1,39 @@ +clusters: + - keyword: "نظام متابعة عملاء السعودية" + intent: commercial + priority: P0 + - keyword: "رد تلقائي واتساب للشركات" + intent: commercial + priority: P0 + - keyword: "CRM عربي للشركات الصغيرة" + intent: commercial + priority: P1 + - keyword: "نظام تأهيل العملاء المحتملين" + intent: informational + priority: P0 + - keyword: "وكالة تسويق شراكة follow-up" + intent: commercial + priority: P0 + - keyword: "متابعة استفسارات العقار" + intent: commercial + priority: P0 + - keyword: "حجز مواعيد تلقائي عيادات" + intent: commercial + priority: P1 + - keyword: "lead response time Saudi Arabia" + intent: informational + priority: P1 + +pages: + - slug: "whatsapp-lead-followup" + keyword: "متابعة واتساب للعملاء" + type: service_page + - slug: "agency-partner-program" + keyword: "برنامج شراكة وكالات" + type: partner_page + - slug: "real-estate-lead-management" + keyword: "إدارة استفسارات العقار" + type: sector_page + - slug: "clinic-booking-followup" + keyword: "حجز مواعيد العيادات" + type: sector_page diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/__init__.py b/salesflow-saas/backend/dealix_marketing_os/engines/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/content_engine.py b/salesflow-saas/backend/dealix_marketing_os/engines/content_engine.py new file mode 100644 index 00000000..418c2b67 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/engines/content_engine.py @@ -0,0 +1,50 @@ +"""Content Engine — generates daily multi-platform content.""" +import yaml +from pathlib import Path + +_pillars_path = Path(__file__).parent.parent / "config" / "content_pillars.yaml" +_pillars = {} +if _pillars_path.exists(): + with open(_pillars_path) as f: + _pillars = yaml.safe_load(f) or {} + +LINKEDIN_TEMPLATES = [ + "كل حملة تجيب leads ثم تضيع بسبب بطء المتابعة هي ميزانية محترقة.\n\nالعميل يرسل واتساب. يتأخر الرد. ما فيه follow-up.\n\nهذا الفراغ اللي Dealix يحله.\n\n#السعودية #B2B #مبيعات", + "60% من استفسارات العملاء في السعودية ما تُتابع خلال أول ساعة.\n\nكلّمت 50+ شركة. النتيجة واحدة: 'ما عندنا وقت نرد على الكل'\n\nالحل مو توظيف أكثر. الحل رد أذكى.", + "سألت مدير مبيعات: 'كم lead تجيك بالشهر؟' قال 200.\n'كم ترد عليه خلال ساعة؟' قال 80.\n120 عميل محتمل ← ضاعوا.\n\nDealix يحفظ 40% منها.", + "الوكالات اللي تقدم lead follow-up كخدمة:\n- Client retention أعلى 40%\n- إيراد إضافي 2,000+ ريال/شهر\n\nبدل ما تنتهي خدمتكم عند الإعلان، أضيفوا متابعة وتحويل.", + "بنيت Dealix بالعربي أولاً. مو ترجمة.\nيفهم 'أبي أعرف السعر' و'وريني' و'كم؟'\n\nلأن العميل السعودي يستاهل منتج مبني له.", +] + +X_TEMPLATES = [ + "الـlead ما يضيع في الإعلان. يضيع في أول 10 دقائق بعد الإعلان.", + "مو AI يستبدل البشر. AI يرد الساعة 2 بالليل.", + "CRM يسجّل بعد المحادثة. بس مين يبدأ المحادثة؟", + "Pilot: 499 ريال. 7 أيام. ضمان استرداد. لأننا نثق بالمنتج.", + "تكلفة SDR: 8,000 ريال/شهر. Dealix: 990 ريال. 24/7. بالعربي.", +] + +IG_STORIES = [ + "إذا عندك واتساب مليان استفسارات — رد بكلمة Demo", + "كم تاخذ ترد على استفسار عميل؟ (poll)", + "قبل Dealix: 60% ضائع. بعد: 5%.", + "Pilot 499 ريال — 7 أيام — ضمان استرداد", + "أطلقت Dealix — يرد على عملائك خلال 45 ثانية 🚀", +] + +def generate_daily_content(day_number: int = 1, theme: str = "") -> dict: + idx = (day_number - 1) % len(LINKEDIN_TEMPLATES) + pillars = _pillars.get("pillars", []) + pillar = pillars[idx % len(pillars)] if pillars else {"name_ar": theme} + + return { + "day": day_number, + "theme": pillar.get("name_ar", theme), + "linkedin": {"post": LINKEDIN_TEMPLATES[idx], "cta": "رد بكلمة Demo أو احجز calendly.com/sami-assiri11/dealix-demo", "approval_required": False}, + "x": {"post": X_TEMPLATES[idx % len(X_TEMPLATES)], "approval_required": False}, + "instagram_story": {"text": IG_STORIES[idx % len(IG_STORIES)], "approval_required": False}, + "whatsapp_status": {"text": f"Dealix يرد على عملائك خلال 45 ثانية 🚀 جرّب: 499 ريال", "approval_required": False}, + "instagram_carousel": {"topic": pillar.get("name_ar", ""), "slides": 5, "status": "idea"}, + "reel_script": {"hook": pillar.get("hook", ""), "duration": "30 sec", "status": "idea"}, + "no_auto_post": True, + } diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/landing_page_engine.py b/salesflow-saas/backend/dealix_marketing_os/engines/landing_page_engine.py new file mode 100644 index 00000000..64e600b8 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/engines/landing_page_engine.py @@ -0,0 +1,19 @@ +"""Landing Page Engine — generates page plans for conversion.""" + +def generate_landing_plans() -> dict: + return { + "pages": [ + {"slug": "/", "type": "homepage", "hero": "ديليكس يحوّل الاستفسارات إلى متابعة وحجز وإيراد", "cta": "احجز ديمو"}, + {"slug": "/marketers", "type": "partner", "hero": "اربح من أول اشتراك مدفوع مؤهل", "cta": "كن شريك Dealix"}, + {"slug": "/partners", "type": "agency", "hero": "أضف خدمة متابعة leads لعملائك", "cta": "احجز مكالمة شراكة"}, + {"slug": "/pricing", "type": "offers", "hero": "باقات بسيطة وواضحة", "cta": "ابدأ Pilot"}, + {"slug": "/use-cases", "type": "sectors", "hero": "كل قطاع عنده leads تضيع", "cta": "احجز ديمو"}, + {"slug": "/trust", "type": "safety", "hero": "الأمان والثقة", "cta": "احجز ديمو آمن"}, + ], + "sector_pages": [ + {"sector": "agencies", "pain": "عملاؤكم يخسرون leads بعد الإعلان"}, + {"sector": "real_estate", "pain": "60% من استفسارات الأسعار تضيع"}, + {"sector": "clinics", "pain": "حجوزات ضائعة من واتساب"}, + {"sector": "ecommerce", "pain": "محادثات ما تتحول لطلبات"}, + ], + } diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/partner_marketing_engine.py b/salesflow-saas/backend/dealix_marketing_os/engines/partner_marketing_engine.py new file mode 100644 index 00000000..374bb00e --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/engines/partner_marketing_engine.py @@ -0,0 +1,20 @@ +"""Partner Marketing Engine — generates partner assets and campaigns.""" + +def generate_partner_assets() -> dict: + return { + "partner_one_pager": { + "headline_ar": "اربح من أول اشتراك مدفوع مؤهل يأتي عن طريقك", + "body_ar": "ديليكس مصمم عشان المسوقين والوكالات يقدرون يستفيدون من شبكتهم. إذا أحلت عميل مؤهل واشترك، تصبح مؤهلاً لعمولة حسب الشروط.", + "earning_paths": [ + {"type": "referral", "desc": "عرّفنا على شركة. لك نسبة بعد الدفع المؤكد."}, + {"type": "reseller", "desc": "بيع Dealix ضمن خدماتك. احتفظ بهامشك."}, + {"type": "service_exchange", "desc": "ساعد بالمحتوى/الإحالات. نعطيك pilot مجاني."}, + ], + "safe_wording": True, + "no_guaranteed_profit": True, + "payout_after_verified_payment": True, + }, + "agency_pitch": "أضف خدمة متابعة leads لعملائك — 20% لك من كل عميل", + "referral_pitch": "لو تعرف شركة تضيع leads، عرّفنا عليها ولك نسبة", + "approval_required": True, + } diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/seo_engine.py b/salesflow-saas/backend/dealix_marketing_os/engines/seo_engine.py new file mode 100644 index 00000000..e109e242 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/engines/seo_engine.py @@ -0,0 +1,26 @@ +"""SEO Engine — generates keyword clusters and content briefs.""" +import yaml +from pathlib import Path + +_seo_path = Path(__file__).parent.parent / "config" / "seo_targets.yaml" +_seo = {} +if _seo_path.exists(): + with open(_seo_path) as f: + _seo = yaml.safe_load(f) or {} + +def generate_seo_plan() -> dict: + clusters = _seo.get("clusters", []) + pages = _seo.get("pages", []) + p0 = [c for c in clusters if c.get("priority") == "P0"] + return { + "total_keywords": len(clusters), + "p0_keywords": len(p0), + "planned_pages": len(pages), + "clusters": clusters, + "pages": pages, + "next_actions": [ + "أنشئ صفحة لكل keyword cluster P0", + "أضف FAQ schema لكل صفحة", + "اربط الصفحات ببعضها (internal links)", + ], + } diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/social_engine.py b/salesflow-saas/backend/dealix_marketing_os/engines/social_engine.py new file mode 100644 index 00000000..0b00d00b --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/engines/social_engine.py @@ -0,0 +1,23 @@ +"""Social Engine — manages multi-platform social media strategy.""" + +PLATFORM_RULES = { + "linkedin": {"frequency": "daily", "type": "founder-led B2B", "automation": "manual only", "dm": "manual max 5/day", "scraping": "PROHIBITED"}, + "x": {"frequency": "daily", "type": "build in public", "automation": "posts allowed, replies manual", "dm": "manual only"}, + "instagram": {"frequency": "3x/week", "type": "visual trust", "automation": "stories manual, no mass DM", "dm": "inbound only"}, + "tiktok": {"frequency": "2x/week", "type": "education/awareness", "automation": "content only, no DM scraping"}, + "whatsapp_status": {"frequency": "daily", "type": "warm network", "automation": "manual"}, +} + +def generate_social_plan(day_number: int = 1) -> dict: + return { + "day": day_number, + "platforms": PLATFORM_RULES, + "daily_tasks": { + "linkedin": "1 post + 5 comments + 3 manual DMs max", + "x": "1 tweet + 5 replies", + "instagram": "1 story (or carousel/reel if scheduled)", + "whatsapp": "update status + 3-5 warm messages", + }, + "prohibited": ["linkedin_scraping", "linkedin_auto_dm", "instagram_mass_dm", "whatsapp_cold_blast", "x_auto_mention"], + "no_auto_post": True, + } diff --git a/salesflow-saas/backend/dealix_marketing_os/engines/strategy_engine.py b/salesflow-saas/backend/dealix_marketing_os/engines/strategy_engine.py new file mode 100644 index 00000000..d9c2a99a --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/engines/strategy_engine.py @@ -0,0 +1,37 @@ +"""Strategy Engine — generates daily marketing strategy based on current state.""" + +SECTOR_PRIORITY = { + "agency": {"priority": 1, "offer": "Agency Add-on Pilot", "channel": "email+linkedin"}, + "real_estate": {"priority": 2, "offer": "Speed-to-Lead Audit", "channel": "email+whatsapp"}, + "clinic": {"priority": 3, "offer": "Booking Follow-up Pilot", "channel": "whatsapp+email"}, + "ecommerce": {"priority": 4, "offer": "Inquiry-to-Order Pilot", "channel": "email+instagram"}, + "website_agency": {"priority": 5, "offer": "Website-to-Lead Add-on", "channel": "linkedin+email"}, +} + +def generate_daily_strategy(verdict: str = "market_execution_ready", day_number: int = 1) -> dict: + themes = ["lost_leads", "whatsapp_followup", "speed_to_lead", "agency_addon", "partner_earning", + "arabic_first", "build_in_public", "revenue_ops", "customer_delivery", "proof_and_safety"] + theme = themes[(day_number - 1) % len(themes)] + sector_keys = sorted(SECTOR_PRIORITY.keys(), key=lambda k: SECTOR_PRIORITY[k]["priority"]) + primary_sector = sector_keys[(day_number - 1) % len(sector_keys)] + sector = SECTOR_PRIORITY[primary_sector] + + return { + "date_index": day_number, + "verdict": verdict, + "strategy_summary": f"يوم {day_number}: ركّز على {primary_sector} مع عرض {sector['offer']}", + "target_segment": primary_sector, + "primary_offer": sector["offer"], + "secondary_offer": "Pilot 499 SAR", + "priority_channels": sector["channel"].split("+"), + "content_theme": theme, + "campaign_goal": "أول 3 ردود إيجابية" if day_number <= 7 else "أول demo", + "daily_minimum": {"touches": 10, "followups": 5, "content": 3, "partner": 1}, + "risks": ["لا إرسال بدون مراجعة", "لا ادعاءات مبالغ فيها"], + "next_actions": [ + f"أرسل 5 إيميلات لقطاع {primary_sector}", + "انشر LinkedIn + X + Instagram", + "تواصل مع وكالة واحدة", + "سجّل في scorecard", + ], + } diff --git a/salesflow-saas/backend/dealix_marketing_os/models/__init__.py b/salesflow-saas/backend/dealix_marketing_os/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/dealix_marketing_os/pipelines/__init__.py b/salesflow-saas/backend/dealix_marketing_os/pipelines/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/dealix_marketing_os/pipelines/daily_marketing_pack_pipeline.py b/salesflow-saas/backend/dealix_marketing_os/pipelines/daily_marketing_pack_pipeline.py new file mode 100644 index 00000000..44a6bcb8 --- /dev/null +++ b/salesflow-saas/backend/dealix_marketing_os/pipelines/daily_marketing_pack_pipeline.py @@ -0,0 +1,26 @@ +"""Daily Marketing Pack — generates complete marketing execution pack.""" +from dealix_marketing_os.engines.strategy_engine import generate_daily_strategy +from dealix_marketing_os.engines.content_engine import generate_daily_content +from dealix_marketing_os.engines.social_engine import generate_social_plan +from dealix_marketing_os.engines.partner_marketing_engine import generate_partner_assets + +def generate_daily_marketing_pack(day_number: int = 1) -> dict: + strategy = generate_daily_strategy(day_number=day_number) + content = generate_daily_content(day_number=day_number, theme=strategy["content_theme"]) + social = generate_social_plan(day_number=day_number) + partner = generate_partner_assets() + + return { + "day": day_number, + "strategy": strategy, + "content": content, + "social": social, + "partner_assets": partner, + "approval_tasks": [ + "LinkedIn post: review before posting", + "Partner pitch: review terms before sending", + "WhatsApp: only send to warm contacts", + ], + "no_auto_post": True, + "no_auto_send": True, + } diff --git a/salesflow-saas/backend/tests/marketing_os/__init__.py b/salesflow-saas/backend/tests/marketing_os/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/salesflow-saas/backend/tests/marketing_os/test_content_engine.py b/salesflow-saas/backend/tests/marketing_os/test_content_engine.py new file mode 100644 index 00000000..151f389e --- /dev/null +++ b/salesflow-saas/backend/tests/marketing_os/test_content_engine.py @@ -0,0 +1,18 @@ +import sys, os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) +from dealix_marketing_os.engines.content_engine import generate_daily_content + +def test_content_generation(): + for day in range(1, 6): + c = generate_daily_content(day_number=day) + assert c["linkedin"]["post"], f"Day {day}: no LinkedIn post" + assert c["x"]["post"], f"Day {day}: no X post" + assert c["instagram_story"]["text"], f"Day {day}: no IG story" + assert c["no_auto_post"] == True, "Must not auto-post" + assert "مضمون" not in c["linkedin"]["post"], "No fake claims in LinkedIn" + assert "guaranteed" not in c["linkedin"]["post"].lower(), "No guaranteed claims" + print(f" ✅ Day {day}: content generated, safe, no auto-post") + print("\n✅ ALL CONTENT TESTS PASSED") + +if __name__ == "__main__": + test_content_generation() diff --git a/salesflow-saas/backend/tests/marketing_os/test_marketing_safety.py b/salesflow-saas/backend/tests/marketing_os/test_marketing_safety.py new file mode 100644 index 00000000..36f0c030 --- /dev/null +++ b/salesflow-saas/backend/tests/marketing_os/test_marketing_safety.py @@ -0,0 +1,33 @@ +import sys, os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) +from dealix_marketing_os.engines.content_engine import generate_daily_content +from dealix_marketing_os.engines.partner_marketing_engine import generate_partner_assets +from dealix_marketing_os.engines.social_engine import generate_social_plan + +def test_no_fake_claims(): + for day in range(1, 6): + c = generate_daily_content(day_number=day) + for text in [c["linkedin"]["post"], c["x"]["post"]]: + for bad in ["مضمون", "guaranteed", "100%", "بدون منافس"]: + assert bad not in text.lower(), f"Fake claim '{bad}' in content" + print(" ✅ No fake claims in content") + +def test_partner_safety(): + p = generate_partner_assets() + assert p.get("partner_one_pager",{}).get("safe_wording") == True, "Partner assets must use safe wording" + assert p.get("partner_one_pager",{}).get("no_guaranteed_profit") == True, "Must not guarantee profit" + assert p.get("partner_one_pager",{}).get("payout_after_verified_payment") == True, "Payout after payment only" + print(" ✅ Partner assets safe") + +def test_social_prohibited(): + s = generate_social_plan() + assert "linkedin_scraping" in s["prohibited"], "LinkedIn scraping must be prohibited" + assert "whatsapp_cold_blast" in s["prohibited"], "WhatsApp blast must be prohibited" + assert s["no_auto_post"] == True, "Must not auto-post" + print(" ✅ Social prohibited actions enforced") + +if __name__ == "__main__": + test_no_fake_claims() + test_partner_safety() + test_social_prohibited() + print("\n✅ ALL MARKETING SAFETY TESTS PASSED") diff --git a/salesflow-saas/backend/tests/marketing_os/test_strategy_engine.py b/salesflow-saas/backend/tests/marketing_os/test_strategy_engine.py new file mode 100644 index 00000000..dedfbf14 --- /dev/null +++ b/salesflow-saas/backend/tests/marketing_os/test_strategy_engine.py @@ -0,0 +1,16 @@ +import sys, os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) +from dealix_marketing_os.engines.strategy_engine import generate_daily_strategy + +def test_strategy(): + for day in range(1, 8): + s = generate_daily_strategy(day_number=day) + assert s["target_segment"], f"Day {day}: no target segment" + assert s["primary_offer"], f"Day {day}: no offer" + assert s["priority_channels"], f"Day {day}: no channels" + assert s["daily_minimum"]["touches"] >= 10, "Min 10 touches" + print(f" ✅ Day {day}: {s['target_segment']} → {s['primary_offer']}") + print("\n✅ ALL STRATEGY TESTS PASSED") + +if __name__ == "__main__": + test_strategy()