feat(platform): close AI expense value loop
Add tenant-safe value, telemetry, connector, commercial, and production-readiness foundations.
This commit is contained in:
@@ -10,6 +10,22 @@ from typing import Any
|
||||
|
||||
import pytest
|
||||
from alembic.config import Config
|
||||
from commercial_migration_assertions import (
|
||||
_assert_commercial_head_schema,
|
||||
_assert_commercial_runtime_invariants,
|
||||
)
|
||||
from financial_connector_migration_assertions import (
|
||||
_assert_financial_connector_head_schema,
|
||||
_assert_financial_connector_runtime_invariants,
|
||||
)
|
||||
from release_telemetry_migration_assertions import (
|
||||
_assert_release_telemetry_head_schema,
|
||||
_assert_release_telemetry_runtime_invariants,
|
||||
)
|
||||
from savings_migration_assertions import (
|
||||
_assert_savings_head_schema,
|
||||
_assert_savings_runtime_invariants,
|
||||
)
|
||||
from sqlalchemy import create_engine, inspect, text
|
||||
from sqlalchemy.engine import Engine, make_url
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
@@ -30,7 +46,7 @@ from app.models.risk_observation import RiskObservation
|
||||
|
||||
MIGRATION_TEST_DATABASE_URL = os.getenv("MIGRATION_TEST_DATABASE_URL", "").strip()
|
||||
LEGACY_PROBE_TABLE = "legacy_migration_probe_records"
|
||||
HEAD_REVISION = "20260716_0014"
|
||||
HEAD_REVISION = "20260717_0028"
|
||||
SERVER_DIR = Path(__file__).resolve().parents[1]
|
||||
ALEMBIC_INI_PATH = SERVER_DIR / "alembic.ini"
|
||||
|
||||
@@ -734,6 +750,10 @@ def _assert_head_schema(engine: Engine) -> None:
|
||||
"attachment_association_jobs",
|
||||
"ck_attachment_association_jobs_generation",
|
||||
)
|
||||
_assert_savings_head_schema(engine)
|
||||
_assert_commercial_head_schema(engine)
|
||||
_assert_financial_connector_head_schema(engine)
|
||||
_assert_release_telemetry_head_schema(engine)
|
||||
|
||||
_assert_indexes(
|
||||
engine,
|
||||
@@ -1486,6 +1506,86 @@ def _assert_historical_case_downgrade_probe(engine: Engine) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _create_legacy_connector_payload_probe(engine: Engine) -> None:
|
||||
with engine.begin() as connection:
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO financial_connector_configs (
|
||||
id, tenant_id, provider, environment, key_version, secret_ref,
|
||||
allowed_event_types_json, clock_skew_seconds, status, created_by
|
||||
) VALUES (
|
||||
'legacy-connector-config', 'tenant-legacy', 'legacy-bank',
|
||||
'mock', 'v1', 'server/legacy', '["payment_settled"]',
|
||||
300, 'active', 'migration-probe'
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO financial_connector_events (
|
||||
id, tenant_id, config_id, provider, environment, direction,
|
||||
external_event_id, event_type, occurred_at, key_version,
|
||||
verification_level, request_fingerprint, content_hash,
|
||||
processing_status, correlation_id,
|
||||
normalized_payload_json, response_json
|
||||
) VALUES (
|
||||
'legacy-connector-event', 'tenant-legacy',
|
||||
'legacy-connector-config', 'legacy-bank', 'mock', 'inbound',
|
||||
'legacy-external', 'payment_settled', now(), 'v1', 'simulated',
|
||||
'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||
'processed', 'legacy-correlation',
|
||||
'{"claim_reference": "BX-SENSITIVE-001", "amount": "66.00"}',
|
||||
'{"accepted": true, "reconciliation_case_id": "legacy-case"}'
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _assert_and_delete_legacy_connector_payload_probe(engine: Engine) -> None:
|
||||
with engine.begin() as connection:
|
||||
row = connection.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT config.version,
|
||||
event.normalized_payload_json::jsonb ? 'claim_reference',
|
||||
event.normalized_payload_json ->> 'amount',
|
||||
event.response_json ->> 'projection_scope'
|
||||
FROM financial_connector_configs AS config
|
||||
JOIN financial_connector_events AS event
|
||||
ON event.config_id = config.id
|
||||
WHERE config.id = 'legacy-connector-config'
|
||||
"""
|
||||
)
|
||||
).one()
|
||||
assert row == (1, False, "66.00", "legacy_nonproduction_effect_unknown")
|
||||
connection.execute(
|
||||
text(
|
||||
"ALTER TABLE financial_connector_events "
|
||||
"DISABLE TRIGGER trg_financial_connector_events_append_only"
|
||||
)
|
||||
)
|
||||
connection.execute(
|
||||
text("DELETE FROM financial_connector_events WHERE id = 'legacy-connector-event'")
|
||||
)
|
||||
connection.execute(
|
||||
text(
|
||||
"ALTER TABLE financial_connector_events "
|
||||
"ENABLE TRIGGER trg_financial_connector_events_append_only"
|
||||
)
|
||||
)
|
||||
connection.execute(
|
||||
text(
|
||||
"DELETE FROM financial_connector_configs "
|
||||
"WHERE id = 'legacy-connector-config'"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _assert_legacy_sentinel(engine: Engine) -> None:
|
||||
assert LEGACY_PROBE_TABLE in _table_names(engine)
|
||||
with engine.connect() as connection:
|
||||
@@ -1524,6 +1624,34 @@ def _assert_base_schema(engine: Engine) -> None:
|
||||
("20260716_0013_approval_tasks.py", "downgrade"),
|
||||
("20260716_0014_risk_waiver_decision.py", "upgrade"),
|
||||
("20260716_0014_risk_waiver_decision.py", "downgrade"),
|
||||
("20260716_0015_savings_value_ledger.py", "upgrade"),
|
||||
("20260716_0015_savings_value_ledger.py", "downgrade"),
|
||||
("20260716_0016_commercial_metering.py", "upgrade"),
|
||||
("20260716_0016_commercial_metering.py", "downgrade"),
|
||||
("20260716_0017_financial_connector_reconciliation.py", "upgrade"),
|
||||
("20260716_0017_financial_connector_reconciliation.py", "downgrade"),
|
||||
("20260716_0018_agent_asset_release_telemetry.py", "upgrade"),
|
||||
("20260716_0018_agent_asset_release_telemetry.py", "downgrade"),
|
||||
("20260716_0019_commercial_runtime_reservations.py", "upgrade"),
|
||||
("20260716_0019_commercial_runtime_reservations.py", "downgrade"),
|
||||
("20260716_0020_financial_connector_config_lifecycle.py", "upgrade"),
|
||||
("20260716_0020_financial_connector_config_lifecycle.py", "downgrade"),
|
||||
("20260716_0021_commercial_billing_periods.py", "upgrade"),
|
||||
("20260716_0021_commercial_billing_periods.py", "downgrade"),
|
||||
("20260716_0022_financial_connector_operational_events.py", "upgrade"),
|
||||
("20260716_0022_financial_connector_operational_events.py", "downgrade"),
|
||||
("20260716_0023_agent_asset_release_blind_audit.py", "upgrade"),
|
||||
("20260716_0023_agent_asset_release_blind_audit.py", "downgrade"),
|
||||
("20260717_0024_commercial_resource_quantity_bases.py", "upgrade"),
|
||||
("20260717_0024_commercial_resource_quantity_bases.py", "downgrade"),
|
||||
("20260717_0025_tenant_identity_foundation.py", "upgrade"),
|
||||
("20260717_0025_tenant_identity_foundation.py", "downgrade"),
|
||||
("20260717_0026_agent_asset_tenant_security.py", "upgrade"),
|
||||
("20260717_0026_agent_asset_tenant_security.py", "downgrade"),
|
||||
("20260717_0027_knowledge_tenant_security.py", "upgrade"),
|
||||
("20260717_0027_knowledge_tenant_security.py", "downgrade"),
|
||||
("20260717_0028_hermes_ontology_tenant_security.py", "upgrade"),
|
||||
("20260717_0028_hermes_ontology_tenant_security.py", "downgrade"),
|
||||
],
|
||||
)
|
||||
def test_postgresql_only_migrations_reject_other_dialects_before_mutation(
|
||||
@@ -1576,6 +1704,142 @@ def test_risk_waiver_migration_refuses_lossy_audit_downgrade() -> None:
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_savings_ledger_migration_refuses_non_empty_fact_downgrade() -> None:
|
||||
migration = _load_migration_module("20260716_0015_savings_value_ledger.py")
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="immutable value facts exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_commercial_migration_refuses_non_empty_contract_or_fact_downgrade() -> None:
|
||||
migration = _load_migration_module("20260716_0016_commercial_metering.py")
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="contracts or immutable facts exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_financial_connector_migration_refuses_non_empty_fact_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0017_financial_connector_reconciliation.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="configurations or immutable facts exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_release_telemetry_migration_refuses_non_empty_fact_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0018_agent_asset_release_telemetry.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="immutable observations or labels exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_runtime_reservation_migration_refuses_non_empty_hold_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0019_commercial_runtime_reservations.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="operational quota holds exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_connector_lifecycle_migration_refuses_lossy_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0020_financial_connector_config_lifecycle.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="versioned configuration state"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_commercial_billing_migration_refuses_non_empty_history_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0021_commercial_billing_periods.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="immutable periods or audit facts exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_connector_operational_migration_refuses_non_empty_history_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0022_financial_connector_operational_events.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="immutable operational facts exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_release_blind_audit_migration_refuses_non_empty_evidence_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260716_0023_agent_asset_release_blind_audit.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="immutable audit evidence exists"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_commercial_resource_basis_migration_refuses_lossy_downgrade() -> None:
|
||||
migration = _load_migration_module(
|
||||
"20260717_0024_commercial_resource_quantity_bases.py"
|
||||
)
|
||||
operation_guard = _UnsupportedDialectOperationGuard(dialect_name="postgresql")
|
||||
operation_guard.bind.scalar = lambda _statement: 1
|
||||
migration.op = operation_guard
|
||||
|
||||
with pytest.raises(RuntimeError, match="resource reservations exist"):
|
||||
migration.downgrade()
|
||||
|
||||
assert operation_guard.mutation_calls == []
|
||||
|
||||
|
||||
def test_head_model_declares_soft_claim_reference_and_organization_only_active_index() -> None:
|
||||
claim_column = RiskObservation.__table__.c.claim_id
|
||||
assert not claim_column.foreign_keys
|
||||
@@ -1707,9 +1971,51 @@ def test_alembic_migration_cycle_on_disposable_postgres(
|
||||
}.isdisjoint(memory_columns)
|
||||
_delete_duplicate_active_organization_memory_probe(engine)
|
||||
|
||||
_upgrade_revision(migration_database_url, "20260716_0019")
|
||||
_create_legacy_connector_payload_probe(engine)
|
||||
_upgrade_head(migration_database_url)
|
||||
_assert_and_delete_legacy_connector_payload_probe(engine)
|
||||
_assert_head_schema(engine)
|
||||
assert validate_migration_state(engine).revision == HEAD_REVISION
|
||||
_assert_savings_runtime_invariants(engine)
|
||||
_assert_commercial_runtime_invariants(engine)
|
||||
_assert_financial_connector_runtime_invariants(engine)
|
||||
_assert_release_telemetry_runtime_invariants(engine)
|
||||
with engine.begin() as connection:
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO profile_baseline_snapshots (
|
||||
id, tenant_id, baseline_key, baseline_type, dimension_type,
|
||||
dimension_id, metric_key, unit, baseline_value, sample_count,
|
||||
method, query_fingerprint, data_quality_status,
|
||||
data_quality_score, algorithm_version, frozen_at, frozen_by
|
||||
) VALUES (
|
||||
'downgrade-refusal-baseline', 'tenant-a',
|
||||
'downgrade-refusal-baseline', 'manual', 'tenant', 'tenant-a',
|
||||
'expense_amount', 'currency', 1, 0, 'migration_probe',
|
||||
'downgrade-refusal-fingerprint', 'complete', 1,
|
||||
'migration-probe-v1', now(), 'migration-probe'
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
with pytest.raises(RuntimeError, match="immutable value facts exist"):
|
||||
_downgrade_revision(migration_database_url, "20260716_0014")
|
||||
assert validate_migration_state(engine).revision == HEAD_REVISION
|
||||
with engine.begin() as connection:
|
||||
assert connection.scalar(
|
||||
text(
|
||||
"SELECT COUNT(*) FROM profile_baseline_snapshots "
|
||||
"WHERE id = 'downgrade-refusal-baseline'"
|
||||
)
|
||||
) == 1
|
||||
connection.execute(
|
||||
text(
|
||||
"DELETE FROM profile_baseline_snapshots "
|
||||
"WHERE id = 'downgrade-refusal-baseline'"
|
||||
)
|
||||
)
|
||||
create_legacy_schema(engine)
|
||||
assert "expense_claims" in _table_names(engine)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user