fix: allow guarded production Flow v2 shadow rebuild

This commit is contained in:
plx
2026-08-16 00:39:23 +00:00
parent 32e7773957
commit e3b8750ebb
4 changed files with 205 additions and 9 deletions

View File

@@ -0,0 +1,104 @@
from inspect import getsource
import pytest
import app.blif_flow_v2_projection_service as projection
import scripts.rebuild_blif_flow_v2_projection as cli
import scripts.simulate_blif_flow_v2 as simulator
def test_help_performs_no_rebuild(monkeypatch, capsys):
monkeypatch.setattr(cli, "validate_execution", lambda **kwargs: pytest.fail("help reached execution"))
with pytest.raises(SystemExit) as exc:
cli.main(["--help"])
assert exc.value.code == 0
assert "--production-shadow" in capsys.readouterr().out
def test_default_execution_does_not_authorize_production():
with pytest.raises(RuntimeError, match="explicit --production-shadow"):
cli.validate_execution(production_shadow=False, mode="shadow", database="clientflow")
@pytest.mark.parametrize("mode", ["", "off", "compare", "authoritative"])
def test_production_shadow_requires_exact_shadow_mode(mode):
with pytest.raises(RuntimeError, match="requires BLIF_FLOW_V2_MODE=shadow"):
cli.validate_execution(production_shadow=True, mode=mode, database="clientflow")
@pytest.mark.parametrize("database", ["clientflow_codex_test", "clientflow_codex_shadow", "other"])
def test_production_shadow_requires_exact_production_database(database):
with pytest.raises(RuntimeError, match="requires database 'clientflow'"):
cli.validate_execution(production_shadow=True, mode="shadow", database=database)
def test_production_shadow_explicit_proof_is_accepted():
cli.validate_execution(production_shadow=True, mode="shadow", database="clientflow")
def test_global_write_allowlist_remains_test_only():
assert projection.WRITE_DATABASE_ALLOWLIST == frozenset({"clientflow_codex_test"})
assert "clientflow" not in projection.WRITE_DATABASE_ALLOWLIST
def test_factual_read_transaction_remains_read_only():
source = getsource(simulator._load)
assert 'conn.execute(text("BEGIN READ ONLY"))' in source
assert 'conn.execute(text("ROLLBACK"))' in source
def test_projection_writer_only_mutates_two_additive_tables():
source = getsource(projection.rebuild_blif_flow_v2_projection).upper()
assert projection.PROJECTION_WRITE_TABLES == {
"opportunity_flow_state_v2", "opportunity_flow_transitions"}
assert "INSERT INTO OPPORTUNITY_FLOW_TRANSITIONS" in source
assert "INSERT INTO OPPORTUNITY_FLOW_STATE_V2" in source
for forbidden in ("OPPORTUNITIES", "TASKS", "MESSAGES", "COMMUNICATIONS",
"COMMERCIAL_DOCUMENTS", "CUSTOMERS", "PAYMENTS", "OPERATION_LINKS"):
assert f"INSERT INTO {forbidden}" not in source
assert f"UPDATE {forbidden}" not in source
assert f"DELETE FROM {forbidden}" not in source
def test_production_derivation_has_no_fixed_328_requirement(monkeypatch):
captured = {}
def fake_collect(**kwargs):
captured.update(kwargs)
return {"opportunities": [{"opportunity_id": "one"}]}
monkeypatch.setattr(simulator, "collect", fake_collect)
rows = projection._derive_all(
expected_database="clientflow", expected_user="runtime-role",
expected_opportunity_count=None, require_opportunities=True,
)
assert rows == [{"opportunity_id": "one"}]
assert captured["expected_opportunity_count"] is None
assert captured["require_opportunities"] is True
def test_snapshot_expected_count_validation_is_still_available(monkeypatch):
monkeypatch.setattr(simulator, "_load", lambda **kwargs: {"opportunities": [object()]})
with pytest.raises(RuntimeError, match="expected 328 opportunities, found 1"):
simulator.collect(expected_opportunity_count=328)
def test_empty_production_universe_is_rejected(monkeypatch):
monkeypatch.setattr(simulator, "collect", lambda **kwargs: {"opportunities": []})
assert projection._derive_all(
expected_database="clientflow", expected_user=None,
expected_opportunity_count=None, require_opportunities=True,
) == []
with pytest.raises(RuntimeError, match="at least one opportunity"):
projection.rebuild_blif_flow_v2_projection(
mode="shadow", derived_rows=[], require_opportunities=True,
)
def test_existing_test_defaults_remain_guarded(monkeypatch):
captured = {}
monkeypatch.setattr(simulator, "collect", lambda **kwargs: captured.update(kwargs) or {"opportunities": []})
projection._derive_all()
assert captured["expected_database"] == "clientflow_codex_test"
assert captured["expected_user"] == "clientflow_codex_test"
assert captured["expected_opportunity_count"] == 328