fix: allow guarded production Flow v2 shadow rebuild
This commit is contained in:
@@ -19,6 +19,7 @@ from app.config import settings
|
||||
|
||||
FLOW_VERSION = "blif-flow-v2-shadow-3"
|
||||
WRITE_DATABASE_ALLOWLIST = frozenset({"clientflow_codex_test"})
|
||||
PROJECTION_WRITE_TABLES = frozenset({"opportunity_flow_state_v2", "opportunity_flow_transitions"})
|
||||
|
||||
|
||||
def _jsonable(value: Any) -> Any:
|
||||
@@ -78,16 +79,24 @@ def _projection_value(row: dict[str, Any], derived_at: datetime) -> dict[str, An
|
||||
return stable | {"source_fingerprint": fingerprint, "derived_at": derived_at}
|
||||
|
||||
|
||||
def _derive_all() -> list[dict[str, Any]]:
|
||||
def _derive_all(
|
||||
*,
|
||||
expected_database: str = "clientflow_codex_test",
|
||||
expected_user: str | None = "clientflow_codex_test",
|
||||
expected_opportunity_count: int | None = 328,
|
||||
require_opportunities: bool = False,
|
||||
) -> list[dict[str, Any]]:
|
||||
# Reuse the validated shadow evidence adapter without making it authoritative.
|
||||
from scripts.simulate_blif_flow_v2 import collect
|
||||
|
||||
report = collect(
|
||||
expected_database="clientflow_codex_test",
|
||||
expected_user="clientflow_codex_test",
|
||||
expected_database=expected_database,
|
||||
expected_user=expected_user,
|
||||
# collect() still opens its factual read phase with BEGIN READ ONLY;
|
||||
# the session default may be read-write in the isolated test database.
|
||||
require_read_only=False,
|
||||
expected_opportunity_count=expected_opportunity_count,
|
||||
require_opportunities=require_opportunities,
|
||||
)
|
||||
return list(report["opportunities"])
|
||||
|
||||
@@ -99,6 +108,10 @@ def rebuild_blif_flow_v2_projection(
|
||||
allowed_databases: frozenset[str] = WRITE_DATABASE_ALLOWLIST,
|
||||
target_schema: str = "public",
|
||||
connection: Any | None = None,
|
||||
derive_expected_database: str = "clientflow_codex_test",
|
||||
derive_expected_user: str | None = "clientflow_codex_test",
|
||||
expected_opportunity_count: int | None = 328,
|
||||
require_opportunities: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Idempotently rebuild projection rows and state-change transitions.
|
||||
|
||||
@@ -114,7 +127,14 @@ def rebuild_blif_flow_v2_projection(
|
||||
if not re.fullmatch(r"[a-z_][a-z0-9_]*", target_schema):
|
||||
raise ValueError("invalid target_schema")
|
||||
|
||||
rows = list(derived_rows) if derived_rows is not None else _derive_all()
|
||||
rows = list(derived_rows) if derived_rows is not None else _derive_all(
|
||||
expected_database=derive_expected_database,
|
||||
expected_user=derive_expected_user,
|
||||
expected_opportunity_count=expected_opportunity_count,
|
||||
require_opportunities=require_opportunities,
|
||||
)
|
||||
if require_opportunities and not rows:
|
||||
raise RuntimeError("Flow v2 projection requires at least one opportunity")
|
||||
derived_at = datetime.now(timezone.utc)
|
||||
values = [_projection_value(row, derived_at) for row in rows]
|
||||
if len({value["opportunity_id"] for value in values}) != len(values):
|
||||
|
||||
Reference in New Issue
Block a user