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

@@ -15,6 +15,7 @@ class Result:
def __init__(self, row): self.row = row
def mappings(self): return self
def one(self): return self.row
def all(self): return self.row if isinstance(self.row, list) else [self.row]
class Connection:
@@ -26,6 +27,8 @@ class Connection:
return Result({"database": self.database, "user": "audit", "transaction_read_only": self.readonly})
if "count(*) FROM opportunities" in sql:
return Result({"opportunities": 328, "projections": 328})
if "GROUP BY business_state" in sql:
return Result([])
return Result({})
def close(self): pass
@@ -37,8 +40,8 @@ class Engine:
def named_decisions(fail=False):
result = {}
for name, (oid, action, queue) in sim.NAMED.items():
result[oid] = {"effective_action": action,
for name, (oid, business_action, action, queue) in sim.NAMED.items():
result[oid] = {"business_next_action": business_action, "effective_action": action,
"operational_queue": "not_current" if queue == "suppressed" else queue,
"suppress_current_card": queue == "suppressed"}
if fail:
@@ -136,3 +139,29 @@ def test_named_case_failure_is_nonzero():
report = sim.build_report(identity={}, configured_mode="compare", v1={"work_items": []},
v2={"work_items": []}, named_decisions=named_decisions(True), missing_projections=0)
assert sim.exit_code(report) != 0
def test_action_changes_correlate_by_material_process_not_action_key():
v1_item = {"work_item_key": "opportunity:o:action:OLD", "opportunity_id": "o",
"action_code": "OLD", "operational_queue": "do_now"}
v2_item = {"work_item_key": "opportunity:o:action:NEW", "opportunity_id": "o",
"canonical_opportunity_id": "o", "action_code": "NEW", "operational_queue": "do_now"}
report = sim.build_report(identity={}, configured_mode="compare",
v1={"work_items": [v1_item]}, v2={"work_items": [v2_item]},
named_decisions=named_decisions(), missing_projections=0)
assert len(report["changed_actions"]) == 1
assert report["removed_cards"] == [] and report["added_cards"] == []
def test_authoritative_material_collapse_selects_one_card_and_retains_evidence():
from app.operations_service import _collapse_authoritative_material_processes
rows = [
{"process_key": "conversation:chatwoot:1863", "work_item_key": "x:SEND_INFO",
"action_code": "SEND_INFO", "operational_queue": "do_now", "source_refs": [{"source": "task", "id": "1"}]},
{"process_key": "conversation:chatwoot:1863", "work_item_key": "x:REVIEW_MANUALLY",
"action_code": "REVIEW_MANUALLY", "operational_queue": "review", "source_refs": [{"source": "communication", "id": "2"}]},
]
result = _collapse_authoritative_material_processes(rows)
assert len(result) == 1
assert result[0]["action_code"] == "REVIEW_MANUALLY"
assert {ref["id"] for ref in result[0]["source_refs"]} == {"1", "2"}