feat: add BLIF Flow v2 shadow compare cutover layer

This commit is contained in:
plx
2026-08-16 00:12:20 +00:00
parent 3b60c3fb70
commit 32e7773957
7 changed files with 417 additions and 24 deletions

View File

@@ -1544,20 +1544,14 @@ def _parse_opportunity_dt(value: object):
def _opportunity_lifecycle_state(opp: dict) -> str:
state = str(opp.get("lifecycle_state") or "active").strip().lower() or "active"
now = datetime.now(timezone.utc)
pending_call = str(opp.get("pending_follow_up_action_code") or "").strip().upper() == "CALL_CUSTOMER"
pending_call_due = _parse_opportunity_dt(opp.get("pending_follow_up_due_at"))
if pending_call:
return "follow_up_due" if pending_call_due and pending_call_due <= now else "scheduled_follow_up"
# Compatibility only: a stale denormalized lifecycle marker cannot invent
# a scheduled call when no active CALL_CUSTOMER task exists.
if state == "scheduled_follow_up":
pending_followup = str(opp.get("pending_follow_up_action_code") or "").strip().upper()
pending_due = _parse_opportunity_dt(opp.get("pending_follow_up_due_at"))
if pending_followup:
return "follow_up_due" if pending_due and pending_due <= now else "scheduled_follow_up"
# Compatibility-only timestamps/lifecycle markers cannot create work. An
# active pending follow-up task and its due_at are the operational source.
if state in {"scheduled_follow_up", "follow_up_due"}:
return "active"
nurture_until = _parse_opportunity_dt(opp.get("nurture_until"))
next_follow_up = _parse_opportunity_dt(opp.get("next_follow_up_at"))
if state == "nurture" and nurture_until and nurture_until <= now:
return "follow_up_due"
if state in {"awaiting_customer", "active", "scheduled_follow_up"} and next_follow_up and next_follow_up <= now:
return "follow_up_due"
return state