fix: harden Flow v2 authoritative cutover semantics

This commit is contained in:
plx
2026-08-16 01:38:39 +00:00
parent ac385342f5
commit 213ba6b41b
7 changed files with 211 additions and 30 deletions

View File

@@ -481,8 +481,8 @@ def _get_authoritative_opportunity_decisions(ids: list[str], *, connection: Any
FROM opportunity_flow_state_v2 WHERE opportunity_id::text IN :opportunity_ids
""", ids)
tasks = _bulk_rows(conn, """
SELECT id::text, opportunity_id::text, action_code, status, due_at,
resolved_at, superseded_by_task_id::text, created_at, metadata
SELECT id::text, opportunity_id::text, action_code, status, due_at, source_system,
resolved_at, resolution_code, superseded_by_task_id::text, created_at, metadata
FROM tasks WHERE opportunity_id::text IN :opportunity_ids AND status = 'pending'
""", ids)
customers = _bulk_rows(conn, """
@@ -514,10 +514,31 @@ def _get_authoritative_opportunity_decisions(ids: list[str], *, connection: Any
reconciliation_blocking=oid in reconciliation_ids,
)
value = decision.to_dict()
winning_ids = {str(ref.get("id") or "") for ref in value.get("obligation_source_refs") or []}
obligation_audit = []
for task in tasks_by_id.get(oid, []):
task_id = str(task.get("id") or "")
if task_id in winning_ids:
classification = "VALID_ACTIVE_OBLIGATION"
elif task.get("superseded_by_task_id"):
classification = "SUPERSEDED_OBLIGATION"
elif task.get("resolved_at") or task.get("resolution_code"):
classification = "SATISFIED_OBLIGATION"
elif ((task_code := str(task.get("action_code") or "").upper()).startswith("SEND_")
and task_code != "SEND_INFO") or task_code == "CREATE_JASMIN_QUOTE":
classification = "PREMATURE_OR_STALE_OBLIGATION"
else:
classification = "STALE_LEGACY_OBLIGATION"
obligation_audit.append({
"id": task_id, "action_code": task.get("action_code"), "status": task.get("status"),
"source_system": task.get("source_system"), "classification": classification,
})
value["obligation_audit_refs"] = obligation_audit
if projection is None:
value["opportunity_id"] = oid
value["target_url"] = f"/opportunities/{oid}"
else:
value["material_process_key"] = projection.get("material_process_key")
value["target_url"] = f"/opportunities/{decision.canonical_opportunity_id or oid}"
decisions[oid] = value
return decisions