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

@@ -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],