B-43: 双边流水归并与规范事件层——迁移5、匹配引擎、个人过账映射与事件API

This commit is contained in:
腾讯WorkBuddy
2026-08-18 21:06:08 +08:00
parent 486842963e
commit df517d4a68
10 changed files with 4565 additions and 49 deletions
+127 -4
View File
@@ -41,7 +41,7 @@ class PersistenceTestCase(unittest.TestCase):
class MigrationTests(PersistenceTestCase):
def test_migrate_creates_schema_and_is_idempotent(self) -> None:
first = applied_versions(self.connection)
self.assertEqual([1, 2, 3, 4], first)
self.assertEqual([1, 2, 3, 4, 5], first)
self.assertEqual([], migrate(self.connection))
self.assertEqual(first, applied_versions(self.connection))
tables = {
@@ -65,19 +65,142 @@ class MigrationTests(PersistenceTestCase):
"sessions",
"login_attempts",
"audit_log",
"personal_transit_mappings",
"canonical_transfer_events",
"transfer_match_decisions",
"transfer_decision_observations",
"transfer_decision_participants",
"transfer_match_candidates",
"current_transfer_decisions",
"transfer_observation_claims",
"schema_migrations",
):
self.assertIn(table, tables)
def test_rollback_removes_schema_and_forward_rebuilds_it(self) -> None:
self.assertEqual([4, 3, 2, 1], rollback(self.connection, 0))
self.assertEqual([5, 4, 3, 2, 1], rollback(self.connection, 0))
self.assertEqual([], applied_versions(self.connection))
remaining = self.connection.execute(
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'source_rows'"
).fetchone()
self.assertIsNone(remaining)
self.assertEqual([1, 2, 3, 4], migrate(self.connection))
self.assertEqual([1, 2, 3, 4], applied_versions(self.connection))
self.assertEqual([1, 2, 3, 4, 5], migrate(self.connection))
self.assertEqual([1, 2, 3, 4, 5], applied_versions(self.connection))
def test_rollback_to_4_keeps_bank_evidence_and_drops_event_layer(self) -> None:
self.import_sample()
row_count = self.connection.execute(
"SELECT COUNT(*) AS n FROM source_rows"
).fetchone()["n"]
self.assertGreater(row_count, 0)
self.assertEqual([5], rollback(self.connection, 4))
# The pre-migration evidence and schema are untouched.
self.assertEqual(
row_count,
self.connection.execute("SELECT COUNT(*) AS n FROM source_rows").fetchone()["n"],
)
self.assertEqual(
"parsed",
self.connection.execute(
"SELECT status FROM import_batches LIMIT 1"
).fetchone()["status"],
)
remaining = self.connection.execute(
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'transfer_match_decisions'"
).fetchone()
self.assertIsNone(remaining)
def test_event_layer_views_exist_after_migration(self) -> None:
view = self.connection.execute(
"SELECT name FROM sqlite_master WHERE type = 'view' AND name = 'eligible_intercompany_events'"
).fetchone()
self.assertIsNotNone(view)
def test_decision_log_immutability_triggers(self) -> None:
self.import_sample()
source_row_id = self.connection.execute(
"SELECT id FROM source_rows LIMIT 1"
).fetchone()["id"]
with self.connection:
self.connection.execute(
"INSERT INTO canonical_transfer_events (lifecycle, created_at) VALUES ('active', ?)",
(utc_now(),),
)
event_id = self.connection.execute(
"SELECT id FROM canonical_transfer_events LIMIT 1"
).fetchone()["id"]
self.connection.execute(
"""
INSERT INTO transfer_match_decisions (
event_id, revision, classification, pairing, mode, rule_version,
locked, created_at
) VALUES (?, 1, 'unresolved', 'not_applicable', 'auto', 'transfer-match-v1', 0, ?)
""",
(event_id, utc_now()),
)
decision_id = self.connection.execute(
"SELECT id FROM transfer_match_decisions LIMIT 1"
).fetchone()["id"]
self.connection.execute(
"""
INSERT INTO transfer_match_candidates (
decision_id, source_row_id, rule_tier, rule_version, created_at
) VALUES (?, ?, 'R1', 'transfer-match-v1', ?)
""",
(decision_id, source_row_id, utc_now()),
)
for statement in (
"UPDATE transfer_match_decisions SET classification = 'external'",
"DELETE FROM transfer_match_decisions",
"UPDATE transfer_match_candidates SET rule_tier = 'M1'",
"DELETE FROM transfer_match_candidates",
"DELETE FROM canonical_transfer_events",
):
with self.subTest(statement=statement):
with self.assertRaises(sqlite3.IntegrityError):
self.connection.execute(statement)
self.connection.rollback()
def test_observation_claims_source_row_is_unique(self) -> None:
self.import_sample()
source_row_id = self.connection.execute(
"SELECT id FROM source_rows LIMIT 1"
).fetchone()["id"]
with self.connection:
self.connection.execute(
"INSERT INTO canonical_transfer_events (lifecycle, created_at) VALUES ('active', ?)",
(utc_now(),),
)
event_id = self.connection.execute(
"SELECT id FROM canonical_transfer_events LIMIT 1"
).fetchone()["id"]
self.connection.execute(
"""
INSERT INTO transfer_match_decisions (
event_id, revision, classification, pairing, mode, locked, created_at
) VALUES (?, 1, 'unresolved', 'not_applicable', 'auto', 0, ?)
""",
(event_id, utc_now()),
)
decision_id = self.connection.execute(
"SELECT id FROM transfer_match_decisions LIMIT 1"
).fetchone()["id"]
self.connection.execute(
"""
INSERT INTO transfer_observation_claims (source_row_id, event_id, decision_id)
VALUES (?, ?, ?)
""",
(source_row_id, event_id, decision_id),
)
with self.assertRaises(sqlite3.IntegrityError):
self.connection.execute(
"""
INSERT INTO transfer_observation_claims (source_row_id, event_id, decision_id)
VALUES (?, ?, ?)
""",
(source_row_id, event_id, decision_id),
)
self.connection.rollback()
class ImportPersistenceTests(PersistenceTestCase):