fix: harden Flow v2 authoritative cutover semantics
This commit is contained in:
@@ -38,6 +38,53 @@ def _int(value: Any) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def _authoritative_material_identity(item: Dict[str, Any]) -> str:
|
||||
return str(item.get("material_process_key") or item.get("canonical_opportunity_id")
|
||||
or item.get("process_key") or item.get("work_item_key") or item.get("id"))
|
||||
|
||||
|
||||
def _collapse_authoritative_material_processes(items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
"""Enforce one current card per material process without deleting evidence."""
|
||||
current_queues = {"do_now", "review", "blocked", "exception"}
|
||||
action_rank = {
|
||||
"REVIEW_MANUALLY": 10, "REVIEW_RECONSTRUCTED_PROCESS": 11, "REVIEW_REQUIRED": 12,
|
||||
"SUPPORT": 20, "SEND_INFO": 30, "CALL_CUSTOMER": 40,
|
||||
"FOLLOW_UP_CUSTOMER_REVIEW": 50, "FOLLOW_UP_PAYMENT": 51,
|
||||
}
|
||||
groups: Dict[str, List[Dict[str, Any]]] = {}
|
||||
noncurrent: List[Dict[str, Any]] = []
|
||||
for item in items:
|
||||
if item.get("operational_queue") not in current_queues:
|
||||
noncurrent.append(item)
|
||||
continue
|
||||
groups.setdefault(_authoritative_material_identity(item), []).append(item)
|
||||
selected: List[Dict[str, Any]] = []
|
||||
for identity, group in groups.items():
|
||||
winner = min(group, key=lambda row: (
|
||||
0 if row.get("operational_queue") in {"blocked", "exception"} else 1,
|
||||
action_rank.get(str(row.get("action_code") or ""), 100),
|
||||
str(row.get("work_item_key") or ""),
|
||||
))
|
||||
merged = dict(winner)
|
||||
if len(group) > 1:
|
||||
merged["suppressed_competing_actions"] = [
|
||||
{"work_item_key": row.get("work_item_key"), "action_code": row.get("action_code"),
|
||||
"source_refs": row.get("source_refs") or []}
|
||||
for row in group if row is not winner
|
||||
]
|
||||
refs, seen = list(merged.get("source_refs") or []), set()
|
||||
for ref in refs:
|
||||
seen.add((str(ref.get("source")), str(ref.get("id"))))
|
||||
for row in group:
|
||||
for ref in row.get("source_refs") or []:
|
||||
key = (str(ref.get("source")), str(ref.get("id")))
|
||||
if key not in seen:
|
||||
refs.append(ref); seen.add(key)
|
||||
merged["source_refs"] = refs
|
||||
selected.append(merged)
|
||||
return selected + noncurrent
|
||||
|
||||
|
||||
def _is_manually_resolved_error(value: Any) -> bool:
|
||||
text_value = str(value or "").strip().casefold()
|
||||
return "limpo manualmente" in text_value or "resolvido manualmente" in text_value
|
||||
@@ -722,6 +769,8 @@ def get_operations_summary(
|
||||
) if opportunity_ids else {})
|
||||
projection = canonicalize_operations(normalized_rows, decisions, evidence_rows=[dict(row) for row in evidence_rows])
|
||||
canonical_items = _attach_operation_urls(list(projection["items"]))
|
||||
if active_flow_mode == "authoritative":
|
||||
canonical_items = _collapse_authoritative_material_processes(canonical_items)
|
||||
partition = partition_canonical_items(canonical_items, display_limit=display_limit)
|
||||
actionable_items = partition["actionable_items"]
|
||||
all_waiting_items = partition["waiting_items"]
|
||||
@@ -750,7 +799,7 @@ def get_operations_summary(
|
||||
"backlog_total": partition["backlog_total"],
|
||||
"not_current_total": partition["not_current_total"],
|
||||
}
|
||||
return {
|
||||
result = {
|
||||
"counts": cleaned_counts,
|
||||
"recent_outbox": [dict(r) for r in recent_outbox],
|
||||
"recent_documents": [dict(r) for r in recent_documents],
|
||||
|
||||
Reference in New Issue
Block a user