#!/usr/bin/env python3 """Real-Postgres G7 smoke using synthetic WAV metadata and the store boundary. Run only against an expendable database. The script creates fixture users/session and intentionally leaves them for the caller to discard with the database. """ from __future__ import annotations # smoke 러너는 앱 패키지를 불러오기 전에 apps/api를 sys.path에 추가해야 한다. # ruff: noqa: E402 import asyncio import hashlib import io import math import struct import sys import wave from datetime import UTC, datetime, timedelta from pathlib import Path from uuid import UUID API_ROOT = Path(__file__).resolve().parents[1] / "apps" / "api" if str(API_ROOT) not in sys.path: sys.path.insert(0, str(API_ROOT)) from app import db from app.contracts.multimodal_alliance import ( FusionCalibration, ModalityAxisMeasurement, ) from app.deps import Principal, Role from app.services import multimodal_alliance_store from app.services.multimodal_alliance import align_voice_timeline LEARNER_ID = UUID("77000000-0000-4000-8000-000000000001") TEACHER_ID = UUID("77000000-0000-4000-8000-000000000002") OUTSIDER_ID = UUID("77000000-0000-4000-8000-000000000003") ADMIN_ID = UUID("77000000-0000-4000-8000-000000000004") SESSION_ID = UUID("77000000-0000-4000-8000-000000000010") CONSENT_SUBMISSION_ID = UUID("77000000-0000-4000-8000-000000000011") TIMELINE_SUBMISSION_ID = UUID("77000000-0000-4000-8000-000000000012") TEXT_ONLY_SUBMISSION_ID = UUID("77000000-0000-4000-8000-000000000013") FUSION_SUBMISSION_ID = UUID("77000000-0000-4000-8000-000000000014") WITHDRAW_SUBMISSION_ID = UUID("77000000-0000-4000-8000-000000000015") COMPLETION_SUBMISSION_ID = UUID("77000000-0000-4000-8000-000000000016") def principal(user_id: UUID, role: Role, cohort: str) -> Principal: return Principal( user_id=str(user_id), role=role, cohort_ids=[cohort], consent_at=1.0, profile_completed_at=1.0, ) def synthetic_wav() -> bytes: sample_rate = 16_000 duration_ms = 1200 frames = sample_rate * duration_ms // 1000 output = io.BytesIO() with wave.open(output, "wb") as writer: writer.setnchannels(1) writer.setsampwidth(2) writer.setframerate(sample_rate) payload = bytearray() for index in range(frames): value = int(3200 * math.sin(2 * math.pi * 220 * index / sample_rate)) payload.extend(struct.pack(" None: pool = db.get_pool() async with pool.acquire() as conn: for user_id, role, cohort in ( (LEARNER_ID, "learner", "g7-cohort"), (TEACHER_ID, "instructor", "g7-cohort"), (OUTSIDER_ID, "instructor", "other-cohort"), (ADMIN_ID, "admin", "admin-cohort"), ): await conn.execute( """ INSERT INTO app.app_user ( user_id, external_id, email, display_name, role, cohort, consent_at, profile_completed_at ) VALUES ($1,$2,$3,$4,$5,$6,now(),now()) ON CONFLICT (user_id) DO NOTHING """, user_id, f"g7-smoke:{user_id}", f"{user_id}@g7-smoke.invalid", "G7 Smoke", role, cohort, ) async with db.acquire( role="learner", user_id=str(LEARNER_ID), cohort_ids=["g7-cohort"], ) as conn: await conn.execute( """ INSERT INTO app.sessions (id, learner_id, theory_mode) VALUES ($1,$2,'integrative') ON CONFLICT (id) DO NOTHING """, SESSION_ID, LEARNER_ID, ) def measurement( *, measurement_id: str, modality: str, value: float, evidence_ref: str, model_run_id: UUID, ) -> ModalityAxisMeasurement: return ModalityAxisMeasurement( measurement_id=measurement_id, axis="bond", modality=modality, status="ready", value=value, confidence=0.82, uncertainty=0.18, evidence_refs=(evidence_ref,), model_run_id=model_run_id, ) async def main() -> None: await db.init_pool() try: await seed_fixture() learner = principal(LEARNER_ID, Role.LEARNER, "g7-cohort") teacher = principal(TEACHER_ID, Role.TEACHER, "g7-cohort") outsider = principal(OUTSIDER_ID, Role.TEACHER, "other-cohort") admin = principal(ADMIN_ID, Role.ADMIN, "admin-cohort") consent = await multimodal_alliance_store.append_consent_snapshot( principal=learner, session_id=SESSION_ID, submission_id=CONSENT_SUBMISSION_ID, consent_status="granted", retain_audio=True, retain_derived_features=True, transcript_retained=True, retention_days=30, policy_version="g7-smoke-v1", reason_code=None, ) replay = await multimodal_alliance_store.append_consent_snapshot( principal=learner, session_id=SESSION_ID, submission_id=CONSENT_SUBMISSION_ID, consent_status="granted", retain_audio=True, retain_derived_features=True, transcript_retained=True, retention_days=30, policy_version="g7-smoke-v1", reason_code=None, ) assert replay["idempotent_replay"] assert consent["consent_snapshot_id"] == replay["consent_snapshot_id"] audio = synthetic_wav() aligned = timeline() audio_asset = { "audio_ref": "g7-smoke://synthetic/one.wav", "audio_sha256": hashlib.sha256(audio).hexdigest(), "media_type": "audio/wav", "byte_size": len(audio), } async with db.acquire(ai_view="evaluator", ai_context=True) as conn: first = await multimodal_alliance_store.append_timeline( conn=conn, session_id=SESSION_ID, submission_id=TIMELINE_SUBMISSION_ID, timeline=aligned, audio_asset=audio_asset, ) async with db.acquire(ai_view="evaluator", ai_context=True) as conn: second = await multimodal_alliance_store.append_timeline( conn=conn, session_id=SESSION_ID, submission_id=TIMELINE_SUBMISSION_ID, timeline=aligned, audio_asset=audio_asset, ) assert second["idempotent_replay"] assert first["timeline_id"] == second["timeline_id"] changed = aligned.model_copy(update={"audio_duration_ms": 1300}) try: async with db.acquire(ai_view="evaluator", ai_context=True) as conn: await multimodal_alliance_store.append_timeline( conn=conn, session_id=SESSION_ID, submission_id=TIMELINE_SUBMISSION_ID, timeline=changed, audio_asset=audio_asset, ) except multimodal_alliance_store.MultimodalAllianceConflictError: pass else: raise AssertionError("changed idempotency payload was not rejected") provenance = { "instrument_id": "alliance-axis-observer", "instrument_version": "g7-smoke-v1", "model_name": "synthetic-observer", "prompt_version": "g7-smoke-v1", } text = measurement( measurement_id="oas-g7-measurement-smoke-text-no-gain", modality="text", value=0.62, evidence_ref="turn:learner:1", model_run_id=UUID("77000000-0000-4000-8000-000000000020"), ) voice = measurement( measurement_id="oas-g7-measurement-smoke-voice-no-gain", modality="voice", value=0.7, evidence_ref="timeline:oas-g7-event-smoke-prosody", model_run_id=UUID("77000000-0000-4000-8000-000000000021"), ) no_gain = FusionCalibration( calibration_id="oas-g7-fusion-smoke-no-gain", axis="bond", text_weight=0.75, voice_weight=0.25, text_only_accuracy=0.81, fused_accuracy=0.815, benchmark_version="g7-benchmark-smoke-v1", minimum_incremental_gain=0.01, ) async with db.acquire(ai_view="evaluator", ai_context=True) as conn: text_only = await multimodal_alliance_store.append_measurement_fusion( conn=conn, session_id=SESSION_ID, submission_id=TEXT_ONLY_SUBMISSION_ID, text=text, voice=voice, calibration=no_gain, text_provenance=provenance, voice_provenance=provenance, ) assert text_only["result"]["modalities_used"] == ["text"] assert not text_only["result"]["fusion_applied"] text_gain = text.model_copy( update={"measurement_id": "oas-g7-measurement-smoke-text-gain"} ) voice_gain = voice.model_copy( update={"measurement_id": "oas-g7-measurement-smoke-voice-gain"} ) gain = no_gain.model_copy( update={ "calibration_id": "oas-g7-fusion-smoke-gain", "fused_accuracy": 0.84, } ) async with db.acquire(ai_view="evaluator", ai_context=True) as conn: fused = await multimodal_alliance_store.append_measurement_fusion( conn=conn, session_id=SESSION_ID, submission_id=FUSION_SUBMISSION_ID, text=text_gain, voice=voice_gain, calibration=gain, text_provenance=provenance, voice_provenance=provenance, ) assert fused["result"]["fusion_applied"] assert set(fused["result"]["modalities_used"]) == {"text", "voice"} learner_view = await multimodal_alliance_store.read_session_metadata( principal=learner, session_id=SESSION_ID ) teacher_view = await multimodal_alliance_store.read_session_metadata( principal=teacher, session_id=SESSION_ID ) assert len(learner_view["voice_events"]) == 4 assert len(teacher_view["voice_events"]) == 4 assert await multimodal_alliance_store.read_raw_audio_access( principal=learner, session_id=SESSION_ID ) try: await multimodal_alliance_store.read_raw_audio_access( principal=teacher, session_id=SESSION_ID ) except multimodal_alliance_store.MultimodalAllianceStateError: pass else: raise AssertionError("teacher unexpectedly received raw audio access") try: await multimodal_alliance_store.read_session_metadata( principal=outsider, session_id=SESSION_ID ) except multimodal_alliance_store.MultimodalAllianceNotFoundError: pass else: raise AssertionError("out-of-cohort teacher unexpectedly saw G7 metadata") assert await multimodal_alliance_store.read_raw_audio_access( principal=admin, session_id=SESSION_ID ) async with db.acquire(ai_view="evaluator", ai_context=True) as conn: expiry_work = ( await multimodal_alliance_store.request_expired_retention_deletions( conn=conn, as_of=datetime.now(UTC) + timedelta(days=31), limit=10, ) ) assert len(expiry_work) == 1 assert not expiry_work[0]["idempotent_replay"] async with db.acquire(ai_view="evaluator", ai_context=True) as conn: expiry_replay = ( await multimodal_alliance_store.request_expired_retention_deletions( conn=conn, as_of=datetime.now(UTC) + timedelta(days=31), limit=10, ) ) assert expiry_replay[0]["idempotent_replay"] assert ( expiry_work[0]["deletion_request_id"] == expiry_replay[0]["deletion_request_id"] ) pool = db.get_pool() async with pool.acquire() as conn: async with conn.transaction(): await conn.execute("SET LOCAL ROLE vignette") public_count = await conn.fetchval( "SELECT count(*) FROM app.multimodal_session_metadata_v" ) assert public_count == 0 withdrawal = await multimodal_alliance_store.append_consent_snapshot( principal=learner, session_id=SESSION_ID, submission_id=WITHDRAW_SUBMISSION_ID, consent_status="withdrawn", retain_audio=False, retain_derived_features=False, transcript_retained=True, retention_days=None, policy_version="g7-smoke-v1", reason_code="learner_withdrawal", ) assert withdrawal["deletion_request_id"] is not None try: await multimodal_alliance_store.assert_voice_processing_allowed( principal=learner, session_id=str(SESSION_ID), ) except multimodal_alliance_store.MultimodalConsentWithdrawnError: pass else: raise AssertionError("withdrawal did not block new voice processing") target_hash = hashlib.sha256( audio_asset["audio_ref"].encode("utf-8") ).hexdigest() async with db.acquire(ai_view="evaluator", ai_context=True) as conn: completed = await multimodal_alliance_store.complete_deletion( conn=conn, deletion_request_id=withdrawal["deletion_request_id"], submission_id=COMPLETION_SUBMISSION_ID, tombstones=( { "scope": "audio", "target_ref_hash": target_hash, "deletion_proof": "synthetic object-store delete acknowledged", "deleted_at": datetime.now(UTC), }, { "scope": "derived_features", "target_ref_hash": hashlib.sha256( str(first["timeline_id"]).encode("utf-8") ).hexdigest(), "deletion_proof": "derived feature access tombstoned", "deleted_at": datetime.now(UTC), }, ), actor_uid=None, actor_kind="retention_worker", ) assert len(completed["tombstone_ids"]) == 2 assert not await multimodal_alliance_store.read_raw_audio_access( principal=learner, session_id=SESSION_ID ) after = await multimodal_alliance_store.read_session_metadata( principal=learner, session_id=SESSION_ID ) assert not after["word_timestamps"] and not after["voice_events"] assert all(item["modality"] == "text" for item in after["measurements"]) assert all( "voice" not in item["modalities_used"] for item in after["fusion_decisions"] ) print( "G7 real DB smoke passed: consent, clock alignment, idempotency, " "fusion gate, RLS, retention sweep, withdrawal, and tombstones" ) finally: await db.close_pool() if __name__ == "__main__": asyncio.run(main())