verify_schema.py
参考源码 · docs/account-system/verify_schema.py
py
"""Validate the reference DDL only; does not implement or certify the API."""
from pathlib import Path
import sqlite3
import tempfile
import threading
import unittest
SCHEMA = Path(__file__).with_name("schema.sql").read_text() + "\n" + Path(__file__).with_name("multiplayer-schema.sql").read_text()
def seed(conn):
for player in ("a", "b"):
conn.execute("INSERT INTO users(id,kind,display_name,created_at,updated_at,last_active_at) VALUES (?, 'guest', ?, 1, 1, 1)", (player, player))
conn.execute("INSERT INTO devices VALUES (?, ?, ?, 'Web', 'web', 1, 1)", (f"dev-{player}", player, f"install-{player}"))
conn.execute("INSERT INTO rule_revisions VALUES ('r1', '{}', ?, 1, 1)", ("1" * 64,))
conn.execute("INSERT INTO content_revisions VALUES ('classic/easy', 'c1', 'classic', '{}', ?)", ("2" * 64,))
conn.execute("INSERT INTO game_runs VALUES ('a', 'run-a', 'run-a', 'classic', 'classic/easy', 'c1', 'r1', '{}', 1)")
conn.commit()
def add_reward(conn, row_id, owner="a", run="run-a", key="run/run-a/terminal"):
conn.execute("INSERT INTO reward_ledger VALUES (?, ?, ?, ?, 'run', 5000, 'r1', 'client_reported', '{}', 1)", (row_id, owner, key, run))
class SchemaContract(unittest.TestCase):
def setUp(self):
self.db = sqlite3.connect(":memory:")
self.db.executescript(SCHEMA)
seed(self.db)
def tearDown(self):
self.db.close()
def reject(self, sql, args=()):
with self.assertRaises(sqlite3.IntegrityError):
self.db.execute(sql, args)
def test_schema_integrity_and_foreign_keys(self):
self.assertEqual(self.db.execute("PRAGMA integrity_check").fetchone()[0], "ok")
self.assertEqual(self.db.execute("PRAGMA foreign_keys").fetchone()[0], 1)
self.assertEqual(self.db.execute("PRAGMA foreign_key_check").fetchall(), [])
def test_account_unique_and_normalized(self):
self.db.execute("INSERT INTO auth_identities VALUES ('i1','a','password','local','player_a',1)")
self.reject("INSERT INTO auth_identities VALUES ('i2','b','password','local','player_a',1)")
self.reject("INSERT INTO auth_identities VALUES ('i3','b','password','local','Player_B',1)")
self.reject("INSERT INTO auth_identities VALUES ('i4','b','password','local','a!',1)")
def test_password_cannot_attach_to_sso_identity(self):
self.db.execute("INSERT INTO auth_identities VALUES ('sso','a','oidc','issuer','subject',1)")
self.reject("INSERT INTO password_credentials VALUES ('sso','$argon2id$example',1)")
def test_cross_player_device_session_rejected(self):
self.reject("INSERT INTO sessions VALUES ('s','a','dev-b',?,?,1,1,1,2,3,NULL)", ("3"*64, "4"*64))
def test_cross_player_reward_run_rejected(self):
with self.assertRaises(sqlite3.IntegrityError):
add_reward(self.db, "reward-wrong", owner="b")
def test_personal_replay_has_no_cloud_table_or_upload_purpose(self):
self.assertIsNone(self.db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='replays'").fetchone())
self.reject("INSERT INTO blobs VALUES ('a','blob-a',?,'identity','replay',1,1,?,1,NULL)", ("5"*64, b"x"))
self.reject("INSERT INTO blobs VALUES ('a','blob-a',?,'identity','evidence',1,1,?,1,NULL)", ("5"*64, b"x"))
def test_cross_player_merge_session_rejected(self):
self.db.execute("INSERT INTO sessions VALUES ('session-b','b','dev-b',?,?,1,1,1,2,3,NULL)", ("3"*64, "4"*64))
self.reject("INSERT INTO merge_tickets VALUES ('ticket','a','session-b',?,10,NULL,NULL)", ("5"*64,))
def test_terminal_unique_and_immutable(self):
self.db.execute("INSERT INTO run_results VALUES ('a','run-a','won','{}',?,'client_reported',1)", ("6"*64,))
self.reject("INSERT INTO run_results VALUES ('a','run-a','lost','{}',?,'client_reported',2)", ("7"*64,))
self.reject("UPDATE run_results SET status='lost' WHERE user_id='a'")
def test_award_unique_and_immutable(self):
add_reward(self.db, "reward-1")
with self.assertRaises(sqlite3.IntegrityError):
add_reward(self.db, "reward-2")
self.reject("UPDATE reward_ledger SET delta_units=10000")
def test_invalid_json_and_negative_totals_rejected(self):
self.reject("INSERT INTO profile_settings VALUES ('a','theme','not-json',1,1)")
self.reject("INSERT INTO player_summary VALUES ('a',-1,0,0,'{}',1,1)")
self.reject("INSERT INTO player_summary VALUES ('a',0,1,2,'{}',1,1)")
def test_blob_length_enforced(self):
self.reject("INSERT INTO blobs VALUES ('a','blob-a',?,'identity','legacy_import',2,2,?,1,NULL)", ("5"*64, b"x"))
def test_reward_and_receipt_rollback_together(self):
self.db.execute("BEGIN IMMEDIATE")
try:
add_reward(self.db, "reward-rollback")
self.db.execute("INSERT INTO sync_operations VALUES ('a','op','dev-a',?,'invalid-json',1)", ("8"*64,))
except sqlite3.IntegrityError:
self.db.rollback()
else:
self.fail("invalid receipt must fail")
self.assertEqual(self.db.execute("SELECT count(*) FROM reward_ledger").fetchone()[0], 0)
def test_cas_and_tombstone_shape(self):
self.db.execute("INSERT INTO save_slots VALUES ('a','slot','run-a','branch','dev-a',1,'{}',1,1,NULL)")
update = "UPDATE save_slots SET snapshot_json=?,version=version+1 WHERE user_id='a' AND slot_id='slot' AND version=? AND deleted_at IS NULL"
self.assertEqual(self.db.execute(update, ('{"elapsed":1}', 1)).rowcount, 1)
self.assertEqual(self.db.execute(update, ('{"elapsed":2}', 1)).rowcount, 0)
self.reject("UPDATE save_slots SET deleted_at=2 WHERE slot_id='slot'")
self.db.execute("UPDATE save_slots SET deleted_at=2,snapshot_json=NULL,version=version+1 WHERE slot_id='slot'")
self.assertEqual(self.db.execute(update, ('{}', 3)).rowcount, 0)
def test_seq_not_reused_after_cleanup(self):
statement = "INSERT INTO sync_changes(user_id,entity_type,entity_id,entity_version,change_json,created_at) VALUES ('a','summary','self',1,'{}',1)"
first = self.db.execute(statement).lastrowid
self.db.execute("DELETE FROM sync_changes")
second = self.db.execute(statement).lastrowid
self.assertGreater(second, first)
def test_two_connections_cannot_duplicate_reward(self):
with tempfile.TemporaryDirectory(prefix="minesweeper-schema-") as directory:
path = str(Path(directory) / "test.sqlite")
setup = sqlite3.connect(path)
setup.executescript(SCHEMA)
setup.execute("PRAGMA journal_mode=WAL")
seed(setup)
setup.close()
start = threading.Barrier(2)
results = []
def attempt(row_id):
conn = sqlite3.connect(path, timeout=5)
conn.execute("PRAGMA foreign_keys=ON")
try:
start.wait(timeout=5)
conn.execute("BEGIN IMMEDIATE")
add_reward(conn, row_id)
conn.commit()
results.append("accepted")
except sqlite3.IntegrityError:
conn.rollback()
results.append("duplicate")
except Exception as error:
results.append(type(error).__name__)
finally:
conn.close()
threads = [threading.Thread(target=attempt, args=(str(i),)) for i in range(2)]
for thread in threads:
thread.start()
for thread in threads:
thread.join(timeout=10)
self.assertFalse(thread.is_alive())
self.assertCountEqual(results, ["accepted", "duplicate"])
check = sqlite3.connect(path)
self.assertEqual(check.execute("SELECT count(*),sum(delta_units) FROM reward_ledger").fetchone(), (1, 5000))
check.close()
class MultiplayerContract(unittest.TestCase):
def setUp(self):
self.db = sqlite3.connect(":memory:")
self.db.executescript(SCHEMA)
seed(self.db)
self.db.execute("UPDATE users SET kind='registered'")
# Deterministic UTC clock for SQL cutoff guards; does not test a real scheduler.
self.clock_ms = 1500
self.db.create_function("strftime", 2, lambda fmt, value: str(self.clock_ms // 1000))
def tearDown(self):
self.db.close()
def reject(self, sql, args=()):
with self.assertRaises(sqlite3.IntegrityError):
self.db.execute(sql, args)
def game(self, key, kind="daily_ranked", owner="a", tier="easy"):
self.db.execute("INSERT INTO online_games(id,kind,status,difficulty,rules_revision,rules_snapshot_json,created_at) VALUES (?,?,'waiting',?,'r1','{}',1)", (key,kind,tier))
self.db.execute("INSERT INTO online_seats(game_id,user_id,seat_no,control_device_id,connection_state,eligibility,remaining_safe_at_start,private_state_json) VALUES (?,?,1,?,'connected','active',10,'{}')", (key,owner,f"dev-{owner}"))
def daily(self, key="daily-a", finished=1500, damage=0, eligible=1, tier="easy", confirmed=1600):
self.game(key,tier=tier)
self.db.execute("INSERT OR IGNORE INTO daily_boards VALUES ('2026-09-13',1000,2000,3000,'open',0,NULL,'r1')")
self.db.execute("INSERT OR IGNORE INTO daily_account_state(user_id,challenge_date,version) VALUES ('a','2026-09-13',1)")
self.db.execute("INSERT OR IGNORE INTO daily_challenges VALUES ('2026-09-13',?,'classic/easy','c1','r1')", (tier,))
self.db.execute("INSERT INTO daily_attempts(game_id,user_id,challenge_date,tier,entry_kind,started_at,finished_at,finished_order,elapsed_ms,initial_health,damage_count,health_lost,status,verification,ranking_eligible,record_complete,confirmed_at) VALUES (?,'a','2026-09-13',?,'ranked',1100,?,1,400,3,?,?,'won','valid',?,1,?)", (key,tier,finished,damage,damage,eligible,confirmed))
def segment(self, key, game):
self.db.execute("INSERT INTO restricted_segments VALUES (?,?,1,3000,'gzip',?,1,3000,1,?,'valid','available',1600)",
(key,game,f"minesweeper:dev:v1:replay:{game}:body:{key}","1"*64))
def submission(self, key="sub", state="awaiting_upload", owner="a"):
self.db.execute("INSERT INTO daily_score_submissions VALUES (?,?,'2026-09-13','overall','e','m','x',1200,1500,1,0,?,?,1500,1900,NULL)", (key,owner,state,"a"*64))
def three(self):
for key,tier in (("e","easy"),("m","medium"),("x","expert")):
self.daily(key,tier=tier)
def grant(self, key="up", submission="sub", owner="a", game="e", expires=1900):
self.db.execute("INSERT INTO daily_replay_uploads(id,submission_id,user_id,game_id,codec,compressed_sha256,content_sha256,compressed_bytes,uncompressed_bytes,redis_key,state,expires_at) VALUES (?,?,?,?,'gzip',?,?,1,1,?,'granted',?)",(key,submission,owner,game,"a"*64,"b"*64,f"minesweeper:dev:v1:replay:{game}:upload:{key}",expires))
def ranking(self):
self.three()
self.db.execute("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',1,'publish',1600)")
self.db.execute("INSERT INTO daily_rankings VALUES ('2026-09-13','overall',1,'a',1,1200,1500,1,'e','m','x')")
self.db.execute("UPDATE daily_boards SET generation=1")
def test_live_tables_game_kind_and_broadcast_scope_absent(self):
self.assertEqual(self.db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'live_%'").fetchall(),[])
with self.assertRaises(sqlite3.IntegrityError):
self.game("unsupported-live","live_classic")
self.reject("INSERT INTO account_restrictions VALUES ('a','broadcast',NULL,'removed','{}',1)")
self.reject("INSERT INTO moderation_cases VALUES ('case','a','live','removed','report','open','removed',NULL,1,NULL)")
def test_watch_requires_replay_and_has_no_live_target(self):
columns={row[1] for row in self.db.execute("PRAGMA table_info(watch_sessions)")}
self.assertNotIn("live_session_id",columns)
self.reject("INSERT INTO watch_sessions(id,anonymous_id_hash,permission_epoch,state,created_at,expires_at) VALUES ('watch',?,1,'waiting',1,2)",("1"*64,))
def test_no_pvp_tables_or_game_kind(self):
self.assertEqual(self.db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'pvp_%'").fetchall(),[])
with self.assertRaises(sqlite3.IntegrityError):
self.game("unsupported","pvp")
def test_one_formal_attempt_per_account(self):
self.game("first")
self.game("second")
self.db.execute("INSERT INTO active_competitions VALUES ('a','first','daily_ranked',1)")
self.reject("INSERT INTO active_competitions VALUES ('a','second','daily_ranked',1)")
def test_guest_cannot_acquire_competitive_slot(self):
self.game("first")
self.db.execute("UPDATE users SET kind='guest' WHERE id='a'")
self.reject("INSERT INTO active_competitions VALUES ('a','first','daily_ranked',1)")
def test_second_seat_not_supported(self):
self.game("daily")
self.reject("INSERT INTO online_seats(game_id,user_id,seat_no,control_device_id,connection_state,eligibility,remaining_safe_at_start,private_state_json) VALUES ('daily','b',2,'dev-b','connected','active',10,'{}')")
def test_damaged_attempt_cannot_be_best(self):
self.daily(damage=1,eligible=0)
self.reject("INSERT INTO daily_bests VALUES ('a','2026-09-13','easy','daily-a')")
self.reject("UPDATE daily_attempts SET ranking_eligible=1 WHERE game_id='daily-a'")
def test_finish_and_validation_both_must_precede_cutoff(self):
self.daily("late-finish",finished=2000)
self.reject("INSERT INTO daily_bests VALUES ('a','2026-09-13','easy','late-finish')")
self.daily("late-verification",confirmed=2000)
self.reject("INSERT INTO daily_bests VALUES ('a','2026-09-13','easy','late-verification')")
def test_best_cannot_replace_with_damaged_attempt(self):
self.daily("good")
self.db.execute("INSERT INTO daily_bests VALUES ('a','2026-09-13','easy','good')")
self.daily("bad",damage=1,eligible=0)
self.reject("UPDATE daily_bests SET game_id='bad'")
def test_today_view_cannot_reuse_same_tier(self):
self.daily()
self.reject("INSERT INTO daily_view_entitlements VALUES ('a','2026-09-13','daily-a','daily-a','daily-a',1600,NULL,1)")
def test_results_append_only(self):
self.game("g")
self.reject("INSERT INTO online_results VALUES ('g',1,'invalid','a','incident','{}',2,2)")
self.db.execute("INSERT INTO online_results VALUES ('g',1,'invalid',NULL,'incident','{}',2,2)")
self.reject("UPDATE online_results SET kind='completion'")
def test_command_sequence_cannot_repeat_under_new_id(self):
self.game("g")
self.db.execute("INSERT INTO online_commands VALUES ('g','a','c1',1,1,?,2,'{}')",("1"*64,))
self.reject("INSERT INTO online_commands VALUES ('g','a','c2',1,1,?,2,'{}')",("1"*64,))
def test_watch_cannot_use_another_accounts_session(self):
self.daily()
self.segment("segment","daily-a")
self.db.execute("INSERT INTO sessions VALUES ('auth-b','b','dev-b',?,?,1,1,1,2,3,NULL)",("3"*64,"4"*64))
self.reject("INSERT INTO watch_sessions(id,user_id,auth_session_id,replay_segment_id,permission_epoch,state,created_at,expires_at) VALUES ('watch','a','auth-b','segment',1,'waiting',1,2)")
def test_published_puzzle_and_mapping_immutable(self):
self.daily()
self.db.execute("INSERT INTO daily_puzzles VALUES ('2026-09-13','easy','g1','v1','{}',?,1,'{}',1,2)",("1"*64,))
self.reject("UPDATE daily_puzzles SET private_map_json='[]'")
self.reject("UPDATE daily_challenges SET rules_revision='r1'")
def test_upload_requires_candidate_and_correct_owner(self):
self.three()
self.submission(state="not_candidate")
with self.assertRaises(sqlite3.IntegrityError):
self.grant()
self.db.execute("UPDATE daily_score_submissions SET status='awaiting_upload'")
with self.assertRaises(sqlite3.IntegrityError):
self.grant(owner="b")
self.grant()
def test_upload_must_belong_to_selected_attempts(self):
self.three()
self.daily("other")
self.submission()
with self.assertRaises(sqlite3.IntegrityError):
self.grant(game="other")
def test_upload_expiry_and_body_size(self):
self.three()
self.submission()
with self.assertRaises(sqlite3.IntegrityError):
self.grant(expires=2001)
self.grant()
self.db.execute("UPDATE daily_replay_uploads SET compressed_bytes=1048576,uncompressed_bytes=8388608")
self.reject("UPDATE daily_replay_uploads SET compressed_bytes=1048577")
self.reject("UPDATE daily_replay_uploads SET redis_key=''")
self.reject("UPDATE daily_replay_uploads SET uncompressed_bytes=8388609")
self.reject("UPDATE daily_replay_uploads SET state='valid',received_at=1600")
self.clock_ms=2000
with self.assertRaises(sqlite3.IntegrityError):
self.grant(key="late",game="m")
def test_pending_combination_unique(self):
self.three()
self.submission()
with self.assertRaises(sqlite3.IntegrityError):
self.submission(key="another")
def test_candidate_does_not_create_ranking(self):
self.three()
self.submission()
self.grant()
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_rankings").fetchone()[0],0)
def test_rank_snapshot_cannot_be_rewritten(self):
self.ranking()
self.reject("UPDATE daily_rankings SET total_ms=1")
self.reject("DELETE FROM daily_rankings")
self.reject("UPDATE daily_rank_revisions SET created_at=1999")
self.reject("DELETE FROM daily_rank_revisions")
def test_published_generation_cannot_receive_extra_rows(self):
self.ranking()
self.db.execute("DELETE FROM daily_rank_annotations")
self.reject("INSERT INTO daily_rankings VALUES ('2026-09-13','overall',1,'b',2,1200,1500,1,'e','m','x')")
self.reject("UPDATE daily_attempts SET elapsed_ms=1 WHERE game_id='e'")
self.reject("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',3,'skip',1700)")
def test_deadline_enforced_even_if_freeze_worker_is_late(self):
self.ranking()
self.clock_ms=2000
self.reject("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',2,'late',1900)")
self.reject("UPDATE daily_boards SET ends_at=4000")
self.reject("UPDATE daily_boards SET generation=2")
self.reject("INSERT INTO daily_bests VALUES ('a','2026-09-13','easy','e')")
self.reject("INSERT INTO daily_rankings VALUES ('2026-09-13','overall',1,'b',2,1200,1500,1,'e','m','x')")
def test_freeze_is_permanent_but_annotation_allowed(self):
self.ranking()
self.reject("UPDATE daily_boards SET status='frozen',frozen_at=2000")
self.clock_ms=2000
self.db.execute("UPDATE daily_boards SET status='frozen',frozen_at=2000")
self.reject("UPDATE daily_boards SET status='open',frozen_at=NULL")
self.db.execute("INSERT INTO daily_rank_annotations VALUES ('note','2026-09-13',1,'overall',1,'disqualified','verified violation',2100)")
self.assertEqual(self.db.execute("SELECT rank,total_ms FROM daily_rankings").fetchone(),(1,1200))
def test_historical_replay_can_have_anonymous_watch_without_entitlement(self):
# SQL allows anonymous playback; date, Top10 and expiry checks belong to API.
self.daily()
self.segment("segment","daily-a")
self.db.execute("INSERT INTO watch_sessions(id,anonymous_id_hash,replay_segment_id,permission_epoch,state,created_at,expires_at) VALUES ('anon',?,'segment',1,'prepared',2100,2200)",("2"*64,))
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_view_entitlements").fetchone()[0],0)
self.assertEqual(self.db.execute("SELECT count(*) FROM watch_exposures").fetchone()[0],0)
def board_row(self, board, generation=1):
ids = {"easy": ("e",None,None), "medium": (None,"m",None),
"expert": (None,None,"x"), "overall": ("e","m","x")}[board]
self.db.execute("INSERT INTO daily_rankings VALUES ('2026-09-13',?,?,'a',1,?,1500,1,?,?,?)",
(board,generation,1200 if board=="overall" else 400,*ids))
def board_submission(self, board, key):
ids = {"easy": ("e",None,None), "medium": (None,"m",None),
"expert": (None,None,"x"), "overall": ("e","m","x")}[board]
self.db.execute("INSERT INTO daily_score_submissions VALUES (?,'a','2026-09-13',?,?,?,?,?,1500,1,0,'awaiting_upload',?,1500,1900,NULL)",
(key,board,*ids,1200 if board=="overall" else 400,"a"*64))
def four_rankings(self):
self.three()
self.db.execute("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',1,'four boards',1600)")
for board in ("easy","medium","expert","overall"):
self.board_row(board)
self.db.execute("UPDATE daily_boards SET generation=1")
def test_single_tier_candidate_needs_only_its_own_replay(self):
self.daily("e")
self.board_submission("easy","single")
self.grant(submission="single")
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_attempts").fetchone()[0],1)
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_rankings").fetchone()[0],0)
def test_one_pending_per_board_not_per_date(self):
self.three()
for board in ("easy","medium","expert","overall"):
self.board_submission(board,board)
with self.assertRaises(sqlite3.IntegrityError):
self.board_submission("easy","duplicate")
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_score_submissions").fetchone()[0],4)
def test_same_user_can_rank_first_on_all_four_boards(self):
self.four_rankings()
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_rankings WHERE user_id='a' AND rank=1").fetchone()[0],4)
def test_single_and_overall_attempt_shapes_are_distinct(self):
self.three()
self.db.execute("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',1,'draft',1600)")
self.reject("INSERT INTO daily_rankings VALUES ('2026-09-13','overall',1,'a',1,400,1500,1,'e',NULL,NULL)")
self.reject("INSERT INTO daily_rankings VALUES ('2026-09-13','easy',1,'a',1,1200,1500,1,'e','m','x')")
self.reject("INSERT INTO daily_rankings VALUES ('2026-09-13','easy',1,'a',1,400,1500,1,NULL,'m',NULL)")
self.board_submission("easy","single")
self.reject("UPDATE daily_score_submissions SET board_kind='overall' WHERE id='single'")
def test_one_replay_is_shared_between_single_and_overall(self):
self.four_rankings()
self.segment("seg","e")
with self.assertRaises(sqlite3.IntegrityError):
self.segment("copy","e")
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_rankings r JOIN restricted_segments s ON r.easy_game_id=s.game_id WHERE s.id='seg'").fetchone()[0],2)
def test_failed_four_board_publication_preserves_previous_snapshot(self):
self.four_rankings()
self.db.commit()
with self.assertRaises(sqlite3.IntegrityError):
with self.db:
self.db.execute("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',2,'update',1700)")
self.board_row("easy",2)
self.board_row("easy",2) # duplicate in same board fails whole transaction
self.db.execute("UPDATE daily_boards SET generation=2")
self.assertEqual(self.db.execute("SELECT generation FROM daily_boards").fetchone()[0],1)
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_rankings WHERE generation=1").fetchone()[0],4)
self.assertEqual(self.db.execute("SELECT count(*) FROM daily_rank_revisions WHERE generation=2").fetchone()[0],0)
def test_freeze_and_annotations_do_not_mix_board_identities(self):
self.four_rankings()
self.clock_ms=2000
self.db.execute("UPDATE daily_boards SET status='frozen',frozen_at=2000")
self.db.execute("INSERT INTO daily_rank_annotations VALUES ('note','2026-09-13',1,'easy',1,'disqualified','violation',2100)")
rows=self.db.execute("SELECT r.board_kind, a.id FROM daily_rankings r LEFT JOIN daily_rank_annotations a USING(challenge_date,generation,board_kind,rank) ORDER BY r.board_kind").fetchall()
self.assertEqual(dict(rows),{"easy":"note","medium":None,"expert":None,"overall":None})
# Service must add overall annotation when the same invalid attempt affects it.
self.reject("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',2,'late',2100)")
def test_overall_can_reference_attempts_from_different_devices(self):
self.three()
self.db.execute("INSERT INTO devices VALUES ('dev-a2','a','install-a2','Tablet','web',1,1)")
self.db.execute("UPDATE online_seats SET control_device_id='dev-a2' WHERE game_id='m'")
self.db.execute("UPDATE daily_attempts SET record_device_id='dev-a2',record_manifest_json='{}' WHERE game_id='m'")
self.reject("UPDATE daily_attempts SET record_device_id='dev-b' WHERE game_id='m'")
self.reject("UPDATE daily_attempts SET record_manifest_json='invalid' WHERE game_id='m'")
self.submission()
self.db.execute("INSERT INTO daily_rank_revisions VALUES ('2026-09-13',1,'multi device',1600)")
self.board_row("overall")
self.assertEqual(self.db.execute("PRAGMA foreign_key_check").fetchall(),[])
def test_replay_tables_have_only_metadata_not_binary_payloads(self):
for table in ("daily_replay_uploads","restricted_segments","restricted_chunks"):
columns={row[1]:row[2] for row in self.db.execute(f"PRAGMA table_info({table})")}
self.assertIn("redis_key",columns)
self.assertNotIn("BLOB",columns.values())
self.assertNotIn("compressed_content",columns)
self.assertNotIn("projected_content",columns)
def test_redis_record_metadata_expiry_and_chunk_key(self):
self.daily()
self.segment("segment","daily-a")
self.db.execute("UPDATE restricted_segments SET compressed_bytes=1048576,uncompressed_bytes=8388608")
self.reject("UPDATE restricted_segments SET compressed_bytes=1048577")
self.reject("UPDATE restricted_segments SET uncompressed_bytes=8388609")
self.reject("UPDATE restricted_segments SET storage_expires_at=4000")
self.reject("UPDATE restricted_segments SET storage_expires_at=1600")
self.db.execute("INSERT INTO restricted_chunks VALUES ('segment',0,0,400,'minesweeper:dev:v1:replay:chunk',20,2000,?)",("1"*64,))
self.reject("INSERT INTO restricted_chunks VALUES ('segment',1,400,800,'minesweeper:dev:v1:replay:chunk',20,2000,?)",("1"*64,))
self.reject("UPDATE restricted_chunks SET byte_length=0")
def test_integrity_of_combined_database(self):
self.ranking()
self.submission()
self.grant()
self.assertEqual(self.db.execute("PRAGMA foreign_key_check").fetchall(),[])
self.assertEqual(self.db.execute("PRAGMA integrity_check").fetchone()[0],"ok")
if __name__ == "__main__":
unittest.main(verbosity=2)