"""Append-only persistence boundary for G5 calibration and unseen transfer.""" from __future__ import annotations import json from collections.abc import Mapping, Sequence from datetime import UTC, datetime from typing import Any, Literal from uuid import UUID, uuid4, uuid5 import asyncpg from .. import db from ..contracts.calibration_transfer import ( ActualTransferExecution, CompetencyCalibrationAssessment, MetacognitivePrescription, NormalizedEvaluatorLabels, TransferVariation, TransferSuiteInput, ) from ..deps import Principal, Role from .calibration_transfer import ( assess_actual_transfer_executions, assess_synthetic_subgroup_drift, assess_transfer, ) from .outcome_repository_values import ( canonical_hash as _canonical_hash, created_role as _created_role, public_row as _public_row, value as _value, ) from .practice_competency import target_techniques class CalibrationTransferNotFoundError(LookupError): pass class CalibrationTransferConflictError(RuntimeError): pass class CalibrationTransferStateError(ValueError): pass _IDEMPOTENCY_TABLES = { "app.calibration_prediction_revision": "prediction_revision_id", "app.calibration_prediction_lock": "lock_id", "app.calibration_performance_observation": "observation_id", "app.calibration_assessment_snapshot": "assessment_snapshot_id", "app.calibration_transfer_suite": "transfer_suite_record_id", "app.calibration_teacher_review_event": "review_id", } _ACTUAL_TRANSFER_NAMESPACE = UUID("4a563cc6-f8d3-51bf-a315-41d2a98b02ce") _ACTUAL_TRANSFER_OBSERVER_VERSION = "calibration-actual-transfer-observer-v1" _ACTUAL_TRANSFER_INSTRUMENT_ID = "unseen-transfer-g5" _ACTUAL_TRANSFER_INSTRUMENT_VERSION = "1.0.0" _POSITIVE_CLIENT_STATES = frozenset( { "affect_contact", "thought_organizing", "responds_to_exploration", "expresses_plan", "defense_loosening", } ) def _ensure_unique_evidence( evidence_turn_ids: Sequence[UUID], *, required: bool = False ) -> tuple[UUID, ...]: normalized = tuple(evidence_turn_ids) if required and not normalized: raise CalibrationTransferStateError("evidence_turn_ids must not be empty") if len(set(normalized)) != len(normalized): raise CalibrationTransferStateError("evidence_turn_ids must be unique") return normalized def _uuid_evidence(refs: Sequence[str], *, required: bool = False) -> tuple[UUID, ...]: values: list[UUID] = [] for ref in refs: try: values.append(UUID(ref)) except (TypeError, ValueError) as exc: raise CalibrationTransferStateError( "G5 evidence refs must be transcript turn UUIDs, never transcript text" ) from exc return _ensure_unique_evidence(values, required=required) async def _existing_by_submission( conn: asyncpg.Connection, *, table: str, submission_id: UUID, content_hash: str, ) -> UUID | None: id_column = _IDEMPOTENCY_TABLES.get(table) if id_column is None: raise AssertionError("unsupported calibration idempotency table") row = await conn.fetchrow( f"SELECT {id_column}, content_hash FROM {table} WHERE submission_id = $1", submission_id, ) if row is None: return None if str(_value(row, "content_hash")) != content_hash: raise CalibrationTransferConflictError( "submission id was already used with different content" ) return UUID(str(_value(row, id_column))) async def _visible_session( conn: asyncpg.Connection, session_id: UUID ) -> Mapping[str, Any]: row = await conn.fetchrow( "SELECT id, learner_id, case_id FROM app.sessions WHERE id = $1", session_id, ) if row is None: raise CalibrationTransferNotFoundError("session not found or not visible") return row async def append_prediction_revision( *, principal: Principal, submission_id: UUID, prediction_revision_id: UUID, history_id: UUID, session_id: UUID, competency_id: str, practice_block_id: str, scenario_variant_id: str, phrase_family_id: str, revision_no: int, supersedes_prediction_revision_id: UUID | None, predicted_success_probability: float, confidence: float, recorded_sequence: int, revision_reason: str, instrument_id: str, instrument_version: str, evidence_turn_ids: Sequence[UUID] = (), ) -> dict[str, Any]: if principal.role != Role.LEARNER: raise CalibrationTransferStateError( "self-prediction revision requires learner role" ) learner_id = UUID(principal.user_id) evidence = _ensure_unique_evidence(evidence_turn_ids) reason = revision_reason.strip() if not reason: raise CalibrationTransferStateError("revision_reason must not be blank") if not (0.0 <= predicted_success_probability <= 1.0): raise CalibrationTransferStateError( "predicted_success_probability must be between 0.0 and 1.0" ) if not (0.0 <= confidence <= 1.0): raise CalibrationTransferStateError( "confidence must be between 0.0 and 1.0" ) if instrument_id == "vignette.calibration-self-prediction": instrument_id = "calibration-mirror-g5" payload = { "prediction_revision_id": str(prediction_revision_id), "history_id": str(history_id), "session_id": str(session_id), "learner_id": str(learner_id), "competency_id": competency_id, "practice_block_id": practice_block_id, "scenario_variant_id": scenario_variant_id, "phrase_family_id": phrase_family_id, "revision_no": revision_no, "supersedes_prediction_revision_id": ( str(supersedes_prediction_revision_id) if supersedes_prediction_revision_id else None ), "predicted_success_probability": predicted_success_probability, "confidence": confidence, "recorded_sequence": recorded_sequence, "revision_reason": reason, "instrument_id": instrument_id, "instrument_version": instrument_version, "evidence_turn_ids": sorted(str(item) for item in evidence), } content_hash = _canonical_hash(payload) async with db.acquire( role=principal.role.value, user_id=principal.user_id, cohort_ids=principal.cohort_ids, ) as conn: session = await _visible_session(conn, session_id) if UUID(str(_value(session, "learner_id"))) != learner_id: raise CalibrationTransferNotFoundError("session does not belong to learner") existing = await _existing_by_submission( conn, table="app.calibration_prediction_revision", submission_id=submission_id, content_hash=content_hash, ) if existing is not None: return { "submission_id": submission_id, "history_id": history_id, "prediction_revision_id": existing, "revision_no": revision_no, "idempotent_replay": True, } await conn.execute( "SELECT pg_advisory_xact_lock(hashtextextended($1::text, 5))", str(history_id), ) history = await conn.fetchrow( "SELECT * FROM app.calibration_prediction_history WHERE history_id = $1", history_id, ) if history is None: if revision_no != 1 or supersedes_prediction_revision_id is not None: raise CalibrationTransferStateError( "new prediction history must start at revision one" ) await conn.execute( """ INSERT INTO app.calibration_prediction_history ( history_id, session_id, learner_id, competency_id, practice_block_id, scenario_variant_id, phrase_family_id, created_by_role ) VALUES ($1,$2,$3,$4,$5,$6,$7,'learner') """, history_id, session_id, learner_id, competency_id, practice_block_id, scenario_variant_id, phrase_family_id, ) else: expected = ( str(session_id), str(learner_id), competency_id, practice_block_id, scenario_variant_id, phrase_family_id, ) actual = ( str(_value(history, "session_id")), str(_value(history, "learner_id")), str(_value(history, "competency_id")), str(_value(history, "practice_block_id")), str(_value(history, "scenario_variant_id")), str(_value(history, "phrase_family_id")), ) if actual != expected: raise CalibrationTransferConflictError( "prediction history target cannot change" ) try: row = await conn.fetchrow( """ INSERT INTO app.calibration_prediction_revision ( prediction_revision_id, submission_id, content_hash, history_id, session_id, learner_id, revision_no, supersedes_prediction_revision_id, predicted_success_probability, confidence, recorded_sequence, revision_reason, instrument_id, instrument_version, evidence_turn_ids, created_by_role ) VALUES ( $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15::uuid[],'learner' ) RETURNING prediction_revision_id, revision_no """, prediction_revision_id, submission_id, content_hash, history_id, session_id, learner_id, revision_no, supersedes_prediction_revision_id, predicted_success_probability, confidence, recorded_sequence, reason, instrument_id, instrument_version, list(evidence), ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "prediction revision submission or chain conflict" ) from exc except ( asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError, asyncpg.ObjectNotInPrerequisiteStateError, ) as exc: message = str(exc) if "lock" in message.lower() or "reveal" in message.lower(): raise CalibrationTransferStateError( f"self-prediction history is locked or revealed: {message}" ) from exc raise CalibrationTransferStateError( "prediction revision violated provenance or history invariants" ) from exc assert row is not None return { "submission_id": submission_id, "history_id": history_id, "prediction_revision_id": UUID( str(_value(row, "prediction_revision_id")) ), "revision_no": int(_value(row, "revision_no")), "idempotent_replay": False, } async def append_prediction_lock( *, principal: Principal, submission_id: UUID, lock_id: UUID, history_id: UUID, prediction_revision_id: UUID, locked_sequence: int, ) -> dict[str, Any]: if principal.role != Role.LEARNER: raise CalibrationTransferStateError("prediction lock requires learner role") learner_id = UUID(principal.user_id) payload = { "lock_id": str(lock_id), "history_id": str(history_id), "prediction_revision_id": str(prediction_revision_id), "locked_sequence": locked_sequence, "learner_id": str(learner_id), } content_hash = _canonical_hash(payload) async with db.acquire( role=principal.role.value, user_id=principal.user_id, cohort_ids=principal.cohort_ids, ) as conn: history = await conn.fetchrow( """ SELECT history_id, session_id, learner_id FROM app.calibration_prediction_history WHERE history_id = $1 """, history_id, ) if history is None or UUID(str(_value(history, "learner_id"))) != learner_id: raise CalibrationTransferNotFoundError( "prediction history not found or not visible" ) existing = await _existing_by_submission( conn, table="app.calibration_prediction_lock", submission_id=submission_id, content_hash=content_hash, ) if existing is not None: return { "submission_id": submission_id, "history_id": history_id, "lock_id": existing, "idempotent_replay": True, } try: row = await conn.fetchrow( """ INSERT INTO app.calibration_prediction_lock ( lock_id, submission_id, content_hash, history_id, prediction_revision_id, session_id, learner_id, locked_sequence, created_by_role ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,'learner') RETURNING lock_id """, lock_id, submission_id, content_hash, history_id, prediction_revision_id, _value(history, "session_id"), learner_id, locked_sequence, ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "prediction lock submission or history conflict" ) from exc except (asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError) as exc: raise CalibrationTransferStateError( "prediction lock must target the latest pre-reveal revision" ) from exc assert row is not None return { "submission_id": submission_id, "history_id": history_id, "lock_id": UUID(str(_value(row, "lock_id"))), "idempotent_replay": False, } async def append_performance_observation( *, conn: asyncpg.Connection, submission_id: UUID, observation_id: UUID, history_id: UUID, status: Literal["passed", "failed", "insufficient_evidence"], source_kind: Literal["model_inferred", "observed_runtime"], perspective: Literal["independent_observer", "runtime_observation"], model_run_id: UUID | None, instrument_id: str, instrument_version: str, uncertainty: float, evidence_turn_ids: Sequence[UUID], counterevidence: Sequence[str], revealed_sequence: int, ) -> dict[str, Any]: evidence = _ensure_unique_evidence( evidence_turn_ids, required=status != "insufficient_evidence" ) if status == "insufficient_evidence" and (evidence or uncertainty != 1.0): raise CalibrationTransferStateError( "insufficient observation must be evidence-free with full uncertainty" ) if status == "failed" and not counterevidence: raise CalibrationTransferStateError( "failed observation requires counterevidence" ) if (source_kind, perspective) not in { ("model_inferred", "independent_observer"), ("observed_runtime", "runtime_observation"), }: raise CalibrationTransferStateError( "performance observation source and perspective are incompatible" ) if source_kind == "model_inferred" and model_run_id is None: raise CalibrationTransferStateError( "model-inferred observation requires model_run_id" ) history = await conn.fetchrow( """ SELECT h.*, l.lock_id FROM app.calibration_prediction_history h JOIN app.calibration_prediction_lock l ON l.history_id = h.history_id WHERE h.history_id = $1 """, history_id, ) if history is None: raise CalibrationTransferNotFoundError( "locked prediction history not found or not visible" ) payload = { "observation_id": str(observation_id), "history_id": str(history_id), "status": status, "source_kind": source_kind, "perspective": perspective, "model_run_id": str(model_run_id) if model_run_id else None, "instrument_id": instrument_id, "instrument_version": instrument_version, "uncertainty": uncertainty, "evidence_turn_ids": sorted(str(item) for item in evidence), "counterevidence": list(counterevidence), "revealed_sequence": revealed_sequence, } content_hash = _canonical_hash(payload) existing = await _existing_by_submission( conn, table="app.calibration_performance_observation", submission_id=submission_id, content_hash=content_hash, ) if existing is not None: return { "submission_id": submission_id, "history_id": history_id, "observation_id": existing, "idempotent_replay": True, } try: row = await conn.fetchrow( """ INSERT INTO app.calibration_performance_observation ( observation_id, submission_id, content_hash, history_id, prediction_lock_id, session_id, learner_id, competency_id, practice_block_id, scenario_variant_id, phrase_family_id, status, source_kind, perspective, model_run_id, instrument_id, instrument_version, uncertainty, evidence_turn_ids, counterevidence, revealed_sequence ) VALUES ( $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18, $19::uuid[],$20::text[],$21 ) RETURNING observation_id """, observation_id, submission_id, content_hash, history_id, _value(history, "lock_id"), _value(history, "session_id"), _value(history, "learner_id"), _value(history, "competency_id"), _value(history, "practice_block_id"), _value(history, "scenario_variant_id"), _value(history, "phrase_family_id"), status, source_kind, perspective, model_run_id, instrument_id, instrument_version, uncertainty, list(evidence), list(counterevidence), revealed_sequence, ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "performance observation submission or reveal conflict" ) from exc except (asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError) as exc: raise CalibrationTransferStateError( "performance observation violated lock, reveal, or provenance invariants" ) from exc assert row is not None return { "submission_id": submission_id, "history_id": history_id, "observation_id": UUID(str(_value(row, "observation_id"))), "idempotent_replay": False, } async def append_calibration_assessment( *, conn: asyncpg.Connection, submission_id: UUID, assessment_snapshot_id: UUID, prescription_id: UUID, session_id: UUID, assessment: CompetencyCalibrationAssessment, prescription: MetacognitivePrescription, source_observation_ids: Sequence[UUID], model_run_id: UUID, instrument_id: str, instrument_version: str, evidence_turn_ids: Sequence[UUID], ) -> dict[str, Any]: if assessment.competency_id != prescription.competency_id: raise CalibrationTransferStateError( "assessment and metacognitive prescription competency must match" ) evidence = _ensure_unique_evidence(evidence_turn_ids) observation_ids = tuple(source_observation_ids) if not observation_ids or len(set(observation_ids)) != len(observation_ids): raise CalibrationTransferStateError( "source_observation_ids must be non-empty and unique" ) session = await _visible_session(conn, session_id) learner_id = UUID(str(_value(session, "learner_id"))) payload = { "assessment_snapshot_id": str(assessment_snapshot_id), "prescription_id": str(prescription_id), "session_id": str(session_id), "learner_id": str(learner_id), "assessment": assessment.model_dump(mode="json"), "prescription": prescription.model_dump(mode="json"), "source_observation_ids": sorted(str(item) for item in observation_ids), "model_run_id": str(model_run_id), "instrument_id": instrument_id, "instrument_version": instrument_version, "evidence_turn_ids": sorted(str(item) for item in evidence), } content_hash = _canonical_hash(payload) existing = await _existing_by_submission( conn, table="app.calibration_assessment_snapshot", submission_id=submission_id, content_hash=content_hash, ) if existing is not None: child = await conn.fetchrow( """ SELECT prescription_id FROM app.calibration_metacognitive_prescription WHERE assessment_snapshot_id = $1 """, existing, ) return { "submission_id": submission_id, "assessment_snapshot_id": existing, "prescription_id": UUID(str(_value(child or {}, "prescription_id"))), "idempotent_replay": True, } latest = await conn.fetchrow( """ SELECT assessment_snapshot_id, snapshot_no FROM app.calibration_assessment_snapshot WHERE learner_id = $1 AND competency_id = $2 ORDER BY snapshot_no DESC LIMIT 1 """, learner_id, assessment.competency_id, ) snapshot_no = int(_value(latest or {}, "snapshot_no", 0)) + 1 supersedes = _value(latest or {}, "assessment_snapshot_id") try: await conn.execute( """ INSERT INTO app.calibration_assessment_snapshot ( assessment_snapshot_id, submission_id, content_hash, session_id, learner_id, competency_id, snapshot_no, supersedes_assessment_snapshot_id, source_observation_ids, assessment_payload, model_run_id, instrument_id, instrument_version, evidence_turn_ids ) VALUES ( $1,$2,$3,$4,$5,$6,$7,$8,$9::uuid[],$10::jsonb,$11,$12,$13,$14::uuid[] ) """, assessment_snapshot_id, submission_id, content_hash, session_id, learner_id, assessment.competency_id, snapshot_no, supersedes, list(observation_ids), assessment.model_dump(mode="json"), model_run_id, instrument_id, instrument_version, list(evidence), ) await conn.execute( """ INSERT INTO app.calibration_metacognitive_prescription ( prescription_id, assessment_snapshot_id, session_id, learner_id, competency_id, prescription_payload, model_run_id, instrument_id, instrument_version, evidence_turn_ids ) VALUES ($1,$2,$3,$4,$5,$6::jsonb,$7,$8,$9,$10::uuid[]) """, prescription_id, assessment_snapshot_id, session_id, learner_id, assessment.competency_id, prescription.model_dump(mode="json"), model_run_id, instrument_id, instrument_version, list(evidence), ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "calibration assessment submission or snapshot conflict" ) from exc except (asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError) as exc: raise CalibrationTransferStateError( "calibration assessment violated source or provenance invariants" ) from exc return { "submission_id": submission_id, "assessment_snapshot_id": assessment_snapshot_id, "prescription_id": prescription_id, "idempotent_replay": False, } async def append_transfer_suite( *, conn: asyncpg.Connection, submission_id: UUID, transfer_suite_record_id: UUID, session_id: UUID, suite: TransferSuiteInput, model_run_id: UUID, instrument_id: str, instrument_version: str, ) -> dict[str, Any]: session = await _visible_session(conn, session_id) learner_id = UUID(str(_value(session, "learner_id"))) payload = { "transfer_suite_record_id": str(transfer_suite_record_id), "session_id": str(session_id), "learner_id": str(learner_id), "suite": suite.model_dump(mode="json"), "model_run_id": str(model_run_id), "instrument_id": instrument_id, "instrument_version": instrument_version, } content_hash = _canonical_hash(payload) existing = await _existing_by_submission( conn, table="app.calibration_transfer_suite", submission_id=submission_id, content_hash=content_hash, ) if existing is not None: counts = await conn.fetchrow( """ SELECT (SELECT count(*) FROM app.calibration_transfer_trial WHERE transfer_suite_record_id = $1) AS trial_count, (SELECT count(*) FROM app.calibration_transfer_assessment WHERE transfer_suite_record_id = $1) AS assessment_count, (SELECT count(*) FROM app.calibration_subgroup_drift_report WHERE transfer_suite_record_id = $1) AS drift_report_count """, existing, ) return { "submission_id": submission_id, "transfer_suite_record_id": existing, "trial_count": int(_value(counts or {}, "trial_count", 0)), "assessment_count": int(_value(counts or {}, "assessment_count", 0)), "drift_report_count": int( _value(counts or {}, "drift_report_count", 0) ), "idempotent_replay": True, } assessments = assess_transfer(suite) drift_reports = assess_synthetic_subgroup_drift(suite) try: await conn.execute( """ INSERT INTO app.calibration_transfer_suite ( transfer_suite_record_id, submission_id, content_hash, suite_key, session_id, learner_id, training_phrase_family_ids, model_run_id, instrument_id, instrument_version ) VALUES ($1,$2,$3,$4,$5,$6,$7::text[],$8,$9,$10) """, transfer_suite_record_id, submission_id, content_hash, suite.suite_id, session_id, learner_id, list(suite.training_phrase_family_ids), model_run_id, instrument_id, instrument_version, ) trial_records: dict[str, tuple[UUID, tuple[UUID, ...]]] = {} for trial in suite.trials: trial_record_id = uuid4() evidence = _uuid_evidence( trial.evidence_refs, required=trial.status != "insufficient_evidence", ) trial_records[trial.trial_id] = (trial_record_id, evidence) await conn.execute( """ INSERT INTO app.calibration_transfer_trial ( transfer_trial_record_id, transfer_suite_record_id, session_id, learner_id, trial_key, competency_id, scenario_variant_id, context_variant, relationship_style, difficulty_level, expression_variant, synthetic_subgroup, scenario_family_id, phrase_family_id, status, uncertainty, evidence_turn_ids, counterevidence, model_run_id, instrument_id, instrument_version ) VALUES ( $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16, $17::uuid[],$18::text[],$19,$20,$21 ) """, trial_record_id, transfer_suite_record_id, session_id, learner_id, trial.trial_id, trial.competency_id, trial.scenario_variant_id, trial.variation.context_variant, trial.variation.relationship_style, trial.variation.difficulty_level, trial.variation.expression_variant, trial.variation.synthetic_subgroup, trial.variation.scenario_family_id, trial.variation.phrase_family_id, trial.status, trial.uncertainty, list(evidence), list(trial.counterevidence), model_run_id, instrument_id, instrument_version, ) for assessment in assessments: source = [ trial_records[trial.trial_id] for trial in suite.trials if trial.competency_id == assessment.competency_id ] source_ids = [item[0] for item in source] evidence = tuple(dict.fromkeys(ref for item in source for ref in item[1])) await conn.execute( """ INSERT INTO app.calibration_transfer_assessment ( transfer_assessment_id, transfer_suite_record_id, session_id, learner_id, competency_id, source_trial_ids, assessment_payload, evidence_turn_ids, model_run_id, instrument_id, instrument_version ) VALUES ($1,$2,$3,$4,$5,$6::uuid[],$7::jsonb,$8::uuid[],$9,$10,$11) """, uuid4(), transfer_suite_record_id, session_id, learner_id, assessment.competency_id, source_ids, assessment.model_dump(mode="json"), list(evidence), model_run_id, instrument_id, instrument_version, ) for report in drift_reports: source = [ trial_records[trial.trial_id] for trial in suite.trials if trial.competency_id == report.competency_id ] await conn.execute( """ INSERT INTO app.calibration_subgroup_drift_report ( drift_report_id, transfer_suite_record_id, session_id, learner_id, competency_id, source_trial_ids, report_payload, model_run_id, instrument_id, instrument_version ) VALUES ($1,$2,$3,$4,$5,$6::uuid[],$7::jsonb,$8,$9,$10) """, uuid4(), transfer_suite_record_id, session_id, learner_id, report.competency_id, [item[0] for item in source], report.model_dump(mode="json"), model_run_id, instrument_id, instrument_version, ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "transfer suite submission or child conflict" ) from exc except (asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError) as exc: raise CalibrationTransferStateError( "transfer suite violated unseen, evidence, or provenance invariants" ) from exc return { "submission_id": submission_id, "transfer_suite_record_id": transfer_suite_record_id, "trial_count": len(suite.trials), "assessment_count": len(assessments), "drift_report_count": len(drift_reports), "idempotent_replay": False, } def _actual_target_techniques(competency_id: str) -> frozenset[str]: targets = target_techniques(competency_id) if targets is not None: return targets raise CalibrationTransferStateError( f"unsupported actual transfer competency: {competency_id}" ) def _actual_execution_from_row(row: Mapping[str, Any]) -> ActualTransferExecution: labels_payload = _value(row, "normalized_evaluator_labels", {}) or {} if isinstance(labels_payload, str): labels_payload = json.loads(labels_payload) return ActualTransferExecution( execution_event_id=UUID(str(_value(row, "execution_event_id"))), original_transfer_trial_record_id=UUID( str(_value(row, "original_transfer_trial_record_id")) ), practice_session_id=UUID(str(_value(row, "practice_session_id"))), competency_id=str(_value(row, "competency_id")), scenario_variant_id=str(_value(row, "scenario_variant_id")), scenario_novelty=str(_value(row, "scenario_novelty")), variation=TransferVariation( context_variant=str(_value(row, "context_variant")), relationship_style=str(_value(row, "relationship_style")), difficulty_level=int(_value(row, "difficulty_level")), expression_variant=str(_value(row, "expression_variant")), synthetic_subgroup=str(_value(row, "synthetic_subgroup")), scenario_family_id=str(_value(row, "scenario_family_id")), phrase_family_id=str(_value(row, "phrase_family_id")), ), status=str(_value(row, "status")), uncertainty=float(_value(row, "uncertainty")), evidence_turn_ids=tuple(_value(row, "evidence_turn_ids", ()) or ()), normalized_evaluator_labels=NormalizedEvaluatorLabels.model_validate( labels_payload ), counterevidence=tuple(_value(row, "counterevidence", ()) or ()), model_run_id=UUID(str(_value(row, "model_run_id"))), source_kind=str(_value(row, "source_kind")), perspective=str(_value(row, "perspective")), instrument_id=str(_value(row, "instrument_id")), instrument_version=str(_value(row, "instrument_version")), observer_version=str(_value(row, "observer_version")), training_phrase_collision=bool( _value(row, "training_phrase_collision", False) ), created_at=_value(row, "created_at") or datetime.now(UTC), ) def _derive_actual_execution_labels( rows: Sequence[Mapping[str, Any]], *, competency_id: str ) -> tuple[ Literal["passed", "failed", "insufficient_evidence"], float, tuple[UUID, ...], NormalizedEvaluatorLabels, tuple[str, ...], ]: targets = _actual_target_techniques(competency_id) technique_codes = tuple( sorted( { str(code) for row in rows for code in (_value(row, "technique_codes", ()) or ()) } ) ) client_state_codes = tuple( sorted( { str(code) for row in rows for code in (_value(row, "client_state_codes", ()) or ()) } ) ) appropriateness = tuple( dict.fromkeys( str(_value(row, "appropriateness", "neutral") or "neutral") for row in rows ) ) deviation_dimensions = tuple( sorted( { str(code).lower() for row in rows for code in ( _value(row, "intent_deviation_dimensions", ()) or () ) if code } ) ) error_count = sum(bool(_value(row, "evaluator_error")) for row in rows) labels = NormalizedEvaluatorLabels( technique_codes=technique_codes, client_state_codes=client_state_codes, appropriateness=appropriateness, intent_deviation_dimensions=deviation_dimensions, evaluator_error_count=error_count, ) complete = [item for item in rows if _value(item, "client_turn_id")] if not complete: return "insufficient_evidence", 1.0, (), labels, () competency_tokens = { token for token in competency_id.lower().replace("competency.", "").replace("-", "_").split("_") if len(token) >= 4 } counterevidence: list[str] = [] passed = False evidence: list[UUID] = [] for row in complete: counselor_id = UUID(str(_value(row, "counselor_turn_id"))) client_id = UUID(str(_value(row, "client_turn_id"))) evidence.extend((counselor_id, client_id)) techniques = set(_value(row, "technique_codes", ()) or ()) states = set(_value(row, "client_state_codes", ()) or ()) dimensions = { str(item).lower() for item in (_value(row, "intent_deviation_dimensions", ()) or ()) if item } target_deviation = any( token in dimension or dimension in token for token in competency_tokens for dimension in dimensions ) technique_match = bool(techniques & targets) client_support = bool(states & _POSITIVE_CLIENT_STATES) row_passed = ( technique_match and _value(row, "appropriateness", "neutral") == "pos" and client_support and not target_deviation and not bool(_value(row, "evaluator_error")) ) passed = passed or row_passed if not technique_match: counterevidence.append("target_technique_not_observed") if _value(row, "appropriateness", "neutral") != "pos": counterevidence.append("appropriateness_not_positive") if not client_support: counterevidence.append("client_response_does_not_support_effect") if target_deviation: counterevidence.append("target_intent_deviation_observed") if _value(row, "evaluator_error"): counterevidence.append("turn_evaluation_error") unique_evidence = tuple(dict.fromkeys(evidence)) if passed: return "passed", 0.25, unique_evidence, labels, () return ( "failed", 0.4, unique_evidence, labels, tuple(dict.fromkeys(counterevidence)) or ("target_behavior_not_observed",), ) async def _actual_events_for_competency( conn: asyncpg.Connection, *, learner_id: UUID, competency_id: str ) -> tuple[ActualTransferExecution, ...]: rows = await conn.fetch( """ SELECT * FROM app.calibration_transfer_execution_event WHERE learner_id = $1 AND competency_id = $2 ORDER BY created_at, execution_event_id """, learner_id, competency_id, ) return tuple(_actual_execution_from_row(row) for row in rows) async def append_actual_transfer_execution( *, principal: Principal, original_transfer_trial_record_id: UUID, practice_session_id: UUID, ) -> dict[str, Any]: """완료된 후속 회기의 정규화 라벨만으로 실제 transfer 실행을 기록한다.""" if principal.role != Role.LEARNER: raise CalibrationTransferStateError( "actual transfer execution requires learner role" ) learner_id = UUID(principal.user_id) event_id = uuid5( _ACTUAL_TRANSFER_NAMESPACE, f"event:{original_transfer_trial_record_id}:{practice_session_id}", ) model_run_id = uuid5( _ACTUAL_TRANSFER_NAMESPACE, f"model:{original_transfer_trial_record_id}:{practice_session_id}", ) async with db.acquire( role=principal.role.value, user_id=principal.user_id, cohort_ids=principal.cohort_ids, ai_context=True, ai_view="evaluator", ) as conn: await conn.execute( "SELECT pg_advisory_xact_lock(hashtextextended($1::text, 5))", f"{original_transfer_trial_record_id}:{practice_session_id}", ) original = await conn.fetchrow( """ SELECT trial.transfer_trial_record_id, trial.transfer_suite_record_id, trial.session_id, trial.learner_id, trial.competency_id, trial.scenario_variant_id, trial.scenario_novelty, trial.context_variant, trial.relationship_style, trial.difficulty_level, trial.expression_variant, trial.synthetic_subgroup, trial.scenario_family_id, trial.phrase_family_id, trial.created_at, suite.training_phrase_family_ids, EXISTS ( SELECT 1 FROM app.calibration_prediction_history history JOIN app.calibration_prediction_lock prediction_lock ON prediction_lock.history_id = history.history_id WHERE history.learner_id = trial.learner_id AND history.competency_id = trial.competency_id AND prediction_lock.created_at <= trial.created_at ) AS prediction_locked FROM app.calibration_transfer_trial trial JOIN app.calibration_transfer_suite suite ON suite.transfer_suite_record_id = trial.transfer_suite_record_id WHERE trial.transfer_trial_record_id = $1 AND trial.learner_id = $2 """, original_transfer_trial_record_id, learner_id, ) if original is None: raise CalibrationTransferNotFoundError( "original transfer trial not found or not visible" ) if not bool(_value(original, "prediction_locked")): raise CalibrationTransferStateError( "self-prediction must be locked before transfer reveal" ) existing = await conn.fetchrow( """ SELECT * FROM app.calibration_transfer_execution_event WHERE original_transfer_trial_record_id = $1 AND practice_session_id = $2 AND learner_id = $3 """, original_transfer_trial_record_id, practice_session_id, learner_id, ) if existing is not None: execution = _actual_execution_from_row(existing) all_events = await _actual_events_for_competency( conn, learner_id=learner_id, competency_id=execution.competency_id, ) assessment = assess_actual_transfer_executions(all_events)[0] return { "execution": execution.model_dump(mode="python"), "assessment": assessment.model_dump(mode="python"), "idempotent_replay": True, } session = await conn.fetchrow( """ SELECT session.id, session.learner_id, session.started_at, session.ended_at, evaluation.status AS evaluation_status, evaluation.scope AS evaluation_scope FROM app.sessions session LEFT JOIN app.session_evaluation evaluation ON evaluation.session_id = session.id WHERE session.id = $1 AND session.learner_id = $2 """, practice_session_id, learner_id, ) if session is None: raise CalibrationTransferNotFoundError( "actual transfer practice session not found or not visible" ) if practice_session_id == UUID(str(_value(original, "session_id"))): raise CalibrationTransferStateError( "actual transfer evidence requires a later practice session" ) if _value(session, "ended_at") is None: raise CalibrationTransferStateError( "actual transfer practice session must be ended" ) if ( _value(session, "evaluation_status") != "ready" or _value(session, "evaluation_scope") != "session_end" ): raise CalibrationTransferStateError( "actual transfer practice evaluation must be ready at session_end" ) if _value(session, "started_at") <= _value(original, "created_at"): raise CalibrationTransferStateError( "actual transfer practice must start after the original trial" ) rows = list( await conn.fetch( """ SELECT counselor.id AS counselor_turn_id, counselor.seq AS counselor_turn_seq, response.id AS client_turn_id, response.seq AS client_turn_seq, ARRAY( SELECT definition.code FROM app.turn_technique tagged JOIN app.technique_label_def definition ON definition.label_id = tagged.label_id WHERE tagged.turn_id = counselor.id ORDER BY definition.code ) AS technique_codes, ARRAY( SELECT definition.code FROM app.turn_client_state tagged JOIN app.client_state_def definition ON definition.label_id = tagged.label_id WHERE tagged.turn_id = response.id ORDER BY definition.code ) AS client_state_codes, CASE WHEN appropriateness.score >= 4 THEN 'pos' WHEN appropriateness.score <= 2 THEN 'warn' ELSE 'neutral' END AS appropriateness, ARRAY( SELECT lower(comment.intent_deviation->>'dimension') FROM app.supervisor_comment comment WHERE comment.turn_id = counselor.id AND comment.intent_deviation IS NOT NULL ORDER BY comment.created_at, comment.id ) AS intent_deviation_dimensions, (evaluator_error.rationale IS NOT NULL) AS evaluator_error FROM app.turns counselor LEFT JOIN LATERAL ( SELECT candidate.id, candidate.seq FROM app.turns candidate WHERE candidate.session_id = counselor.session_id AND candidate.speaker = 'client' AND candidate.seq > counselor.seq ORDER BY candidate.seq LIMIT 1 ) response ON TRUE LEFT JOIN LATERAL ( SELECT score FROM app.feedback_scores score WHERE score.turn_id = counselor.id AND score.dimension = 'appropriateness' ORDER BY score.created_at DESC LIMIT 1 ) appropriateness ON TRUE LEFT JOIN LATERAL ( SELECT rationale FROM app.feedback_scores score WHERE score.turn_id = counselor.id AND score.dimension = 'error' ORDER BY score.created_at DESC LIMIT 1 ) evaluator_error ON TRUE WHERE counselor.session_id = $1 AND counselor.speaker = 'counselor' ORDER BY counselor.seq """, practice_session_id, ) ) competency_id = str(_value(original, "competency_id")) status_value, uncertainty, evidence, labels, counterevidence = ( _derive_actual_execution_labels(rows, competency_id=competency_id) ) label_payload = labels.model_dump(mode="json") evidence_payload = { "observer_version": _ACTUAL_TRANSFER_OBSERVER_VERSION, "original_transfer_trial_record_id": str( original_transfer_trial_record_id ), "practice_session_id": str(practice_session_id), "competency_id": competency_id, "evidence_turn_ids": [str(item) for item in evidence], "normalized_evaluator_labels": label_payload, } await conn.execute( """ INSERT INTO audit.model_run ( model_run_id, session_id, agent_role, provider, model, prompt_bundle_id, prompt_bundle_version, prompt_bundle_hash, structured_schema_version, input_evidence_hash, status, metadata ) VALUES ( $1,$2,'evaluator','vignette-runtime','calibration-actual-transfer-observer', 'calibration-actual-transfer-observer',$3,$4, 'vignette.calibration-actual-transfer-execution.v1',$5,'ready',$6::jsonb ) ON CONFLICT (model_run_id) DO NOTHING """, model_run_id, practice_session_id, _ACTUAL_TRANSFER_OBSERVER_VERSION, _canonical_hash( {"observer_version": _ACTUAL_TRANSFER_OBSERVER_VERSION} ), _canonical_hash(evidence_payload), evidence_payload, ) training_phrases = set( _value(original, "training_phrase_family_ids", ()) or () ) try: inserted = await conn.fetchrow( """ INSERT INTO app.calibration_transfer_execution_event ( execution_event_id, original_transfer_trial_record_id, transfer_suite_record_id, practice_session_id, learner_id, competency_id, scenario_variant_id, context_variant, relationship_style, difficulty_level, expression_variant, synthetic_subgroup, scenario_family_id, phrase_family_id, training_phrase_collision, status, uncertainty, evidence_turn_ids, normalized_evaluator_labels, counterevidence, model_run_id, source_kind, perspective, instrument_id, instrument_version, observer_version ) VALUES ( $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17, $18::uuid[],$19::jsonb,$20::text[],$21,$22,$23,$24,$25,$26 ) RETURNING * """, event_id, original_transfer_trial_record_id, _value(original, "transfer_suite_record_id"), practice_session_id, learner_id, competency_id, _value(original, "scenario_variant_id"), _value(original, "context_variant"), _value(original, "relationship_style"), _value(original, "difficulty_level"), _value(original, "expression_variant"), _value(original, "synthetic_subgroup"), _value(original, "scenario_family_id"), _value(original, "phrase_family_id"), _value(original, "phrase_family_id") in training_phrases, status_value, uncertainty, list(evidence), label_payload, list(counterevidence), model_run_id, "model_inferred", "independent_observer", _ACTUAL_TRANSFER_INSTRUMENT_ID, _ACTUAL_TRANSFER_INSTRUMENT_VERSION, _ACTUAL_TRANSFER_OBSERVER_VERSION, ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "actual transfer practice session was already recorded" ) from exc except (asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError) as exc: raise CalibrationTransferStateError( "actual transfer execution violated source or evidence invariants" ) from exc assert inserted is not None execution = _actual_execution_from_row(inserted) all_events = await _actual_events_for_competency( conn, learner_id=learner_id, competency_id=competency_id ) assessment = assess_actual_transfer_executions(all_events)[0] return { "execution": execution.model_dump(mode="python"), "assessment": assessment.model_dump(mode="python"), "idempotent_replay": False, } async def append_teacher_review( *, principal: Principal, submission_id: UUID, review_id: UUID, target_kind: Literal[ "calibration_assessment", "transfer_assessment", "drift_report" ], target_id: UUID, disposition: Literal["confirmed", "corrected", "needs_more_evidence"], correction_payload: Mapping[str, Any], review_reason: str, evidence_turn_ids: Sequence[UUID], counterevidence: Sequence[str], ) -> dict[str, Any]: if principal.role not in {Role.TEACHER, Role.ADMIN}: raise CalibrationTransferStateError( "calibration review requires teacher or admin role" ) reason = review_reason.strip() if not reason: raise CalibrationTransferStateError("review_reason must not be blank") if disposition != "corrected" and correction_payload: raise CalibrationTransferStateError( "only corrected reviews may carry correction_payload" ) evidence = _ensure_unique_evidence(evidence_turn_ids) target_tables = { "calibration_assessment": ( "app.calibration_assessment_snapshot", "assessment_snapshot_id", ), "transfer_assessment": ( "app.calibration_transfer_assessment", "transfer_assessment_id", ), "drift_report": ( "app.calibration_subgroup_drift_report", "drift_report_id", ), } table, id_column = target_tables[target_kind] payload = { "review_id": str(review_id), "target_kind": target_kind, "target_id": str(target_id), "disposition": disposition, "correction_payload": dict(correction_payload), "review_reason": reason, "evidence_turn_ids": sorted(str(item) for item in evidence), "counterevidence": list(counterevidence), "created_by_uid": principal.user_id, } content_hash = _canonical_hash(payload) async with db.acquire( role=principal.role.value, user_id=principal.user_id, cohort_ids=principal.cohort_ids, ) as conn: target = await conn.fetchrow( f"SELECT session_id, learner_id FROM {table} WHERE {id_column} = $1", target_id, ) if target is None: raise CalibrationTransferNotFoundError( "review target not found or outside cohort scope" ) existing = await _existing_by_submission( conn, table="app.calibration_teacher_review_event", submission_id=submission_id, content_hash=content_hash, ) if existing is not None: row = await conn.fetchrow( "SELECT review_no FROM app.calibration_teacher_review_event WHERE review_id = $1", existing, ) return { "submission_id": submission_id, "review_id": existing, "review_no": int(_value(row or {}, "review_no", 1)), "idempotent_replay": True, } latest = await conn.fetchrow( """ SELECT review_id, review_no FROM app.calibration_teacher_review_event WHERE target_kind = $1 AND target_id = $2 ORDER BY review_no DESC LIMIT 1 """, target_kind, target_id, ) review_no = int(_value(latest or {}, "review_no", 0)) + 1 try: row = await conn.fetchrow( """ INSERT INTO app.calibration_teacher_review_event ( review_id, submission_id, content_hash, target_kind, target_id, session_id, learner_id, review_no, supersedes_review_id, disposition, correction_payload, review_reason, evidence_turn_ids, counterevidence, created_by_uid, created_by_role ) VALUES ( $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12, $13::uuid[],$14::text[],$15,$16 ) RETURNING review_id, review_no """, review_id, submission_id, content_hash, target_kind, target_id, _value(target, "session_id"), _value(target, "learner_id"), review_no, _value(latest or {}, "review_id"), disposition, dict(correction_payload), reason, list(evidence), list(counterevidence), UUID(principal.user_id), _created_role(principal), ) except asyncpg.UniqueViolationError as exc: raise CalibrationTransferConflictError( "teacher review submission or supersession conflict" ) from exc except (asyncpg.CheckViolationError, asyncpg.ForeignKeyViolationError) as exc: raise CalibrationTransferStateError( "teacher review violated target, evidence, or payload invariants" ) from exc assert row is not None return { "submission_id": submission_id, "review_id": UUID(str(_value(row, "review_id"))), "review_no": int(_value(row, "review_no")), "idempotent_replay": False, } async def read_calibration_transfer( *, principal: Principal, learner_id: UUID | None = None ) -> dict[str, Any]: if principal.role == Role.LEARNER: target_learner_id = UUID(principal.user_id) if learner_id is not None and learner_id != target_learner_id: raise CalibrationTransferNotFoundError( "learner calibration is not visible" ) requested_view = "learner" elif principal.role in {Role.TEACHER, Role.ADMIN}: if learner_id is None: raise CalibrationTransferStateError( "teacher/admin calibration read requires learner_id" ) target_learner_id = learner_id requested_view = "supervisor" else: raise CalibrationTransferStateError("unsupported calibration reader role") async with db.acquire( role=principal.role.value, user_id=principal.user_id, cohort_ids=principal.cohort_ids, ) as conn: if principal.role in {Role.TEACHER, Role.ADMIN}: visible = await conn.fetchval( "SELECT EXISTS(SELECT 1 FROM app.sessions WHERE learner_id = $1)", target_learner_id, ) if not visible: raise CalibrationTransferNotFoundError( "learner calibration not found or outside cohort scope" ) histories = list( await conn.fetch( """ SELECT history.history_id, history.session_id, history.competency_id, history.practice_block_id, history.scenario_variant_id, history.phrase_family_id, history.created_at, source_session.learner_feedback_enabled AS source_learner_feedback_enabled FROM app.calibration_prediction_history history JOIN app.sessions source_session ON source_session.id = history.session_id WHERE history.learner_id = $1 ORDER BY history.created_at, history.history_id """, target_learner_id, ) ) history_ids = [UUID(str(_value(item, "history_id"))) for item in histories] revisions = ( list( await conn.fetch( """ SELECT prediction_revision_id, submission_id, history_id, revision_no, supersedes_prediction_revision_id, predicted_success_probability, confidence, recorded_sequence, revision_reason, source_kind, perspective, instrument_id, instrument_version, evidence_turn_ids, created_at FROM app.calibration_prediction_revision WHERE history_id = ANY($1::uuid[]) ORDER BY history_id, revision_no """, history_ids, ) ) if history_ids else [] ) locks = ( list( await conn.fetch( """ SELECT lock_id, submission_id, history_id, prediction_revision_id, locked_sequence, created_at FROM app.calibration_prediction_lock WHERE history_id = ANY($1::uuid[]) """, history_ids, ) ) if history_ids else [] ) observations = ( list( await conn.fetch( """ SELECT observation_id, submission_id, history_id, status, source_kind, perspective, model_run_id, instrument_id, instrument_version, uncertainty, evidence_turn_ids, counterevidence, revealed_sequence, created_at FROM app.calibration_performance_observation WHERE history_id = ANY($1::uuid[]) """, history_ids, ) ) if history_ids else [] ) assessments = list( await conn.fetch( """ SELECT a.assessment_snapshot_id, a.submission_id, a.session_id, a.competency_id, a.snapshot_no, a.supersedes_assessment_snapshot_id, a.source_observation_ids, a.assessment_payload, a.model_run_id, a.instrument_id, a.instrument_version, a.evidence_turn_ids, a.created_at, p.prescription_id, p.prescription_payload, source_session.learner_feedback_enabled AS source_learner_feedback_enabled FROM app.calibration_assessment_snapshot a JOIN app.calibration_metacognitive_prescription p ON p.assessment_snapshot_id = a.assessment_snapshot_id JOIN app.sessions source_session ON source_session.id = a.session_id WHERE a.learner_id = $1 ORDER BY a.competency_id, a.snapshot_no """, target_learner_id, ) ) suites = list( await conn.fetch( """ SELECT suite.transfer_suite_record_id, suite.submission_id, suite.suite_key, suite.session_id, suite.training_phrase_family_ids, suite.model_run_id, suite.instrument_id, suite.instrument_version, suite.data_classification, suite.clinical_claim_allowed, suite.created_at, source_session.learner_feedback_enabled AS source_learner_feedback_enabled FROM app.calibration_transfer_suite suite JOIN app.sessions source_session ON source_session.id = suite.session_id WHERE suite.learner_id = $1 ORDER BY suite.created_at, suite.transfer_suite_record_id """, target_learner_id, ) ) suite_ids = [ UUID(str(_value(item, "transfer_suite_record_id"))) for item in suites ] trials = ( list( await conn.fetch( """ SELECT transfer_trial_record_id, transfer_suite_record_id, trial_key, competency_id, scenario_variant_id, scenario_novelty, context_variant, relationship_style, difficulty_level, expression_variant, synthetic_subgroup, scenario_family_id, phrase_family_id, status, uncertainty, evidence_turn_ids, counterevidence, model_run_id, instrument_id, instrument_version, created_at FROM app.calibration_transfer_trial WHERE transfer_suite_record_id = ANY($1::uuid[]) ORDER BY transfer_suite_record_id, created_at, transfer_trial_record_id """, suite_ids, ) ) if suite_ids else [] ) transfer_assessments = ( list( await conn.fetch( """ SELECT transfer_assessment_id, transfer_suite_record_id, competency_id, source_trial_ids, assessment_payload, evidence_turn_ids, model_run_id, instrument_id, instrument_version, created_at FROM app.calibration_transfer_assessment WHERE transfer_suite_record_id = ANY($1::uuid[]) ORDER BY transfer_suite_record_id, competency_id """, suite_ids, ) ) if suite_ids else [] ) drift_reports = ( list( await conn.fetch( """ SELECT drift_report_id, transfer_suite_record_id, competency_id, source_trial_ids, report_payload, model_run_id, instrument_id, instrument_version, data_classification, clinical_claim_allowed, created_at FROM app.calibration_subgroup_drift_report WHERE transfer_suite_record_id = ANY($1::uuid[]) ORDER BY transfer_suite_record_id, competency_id """, suite_ids, ) ) if suite_ids else [] ) reviews = list( await conn.fetch( """ SELECT review_id, submission_id, target_kind, target_id, review_no, supersedes_review_id, disposition, correction_payload, review_reason, evidence_turn_ids, counterevidence, created_by_uid, created_by_role, created_at FROM app.calibration_teacher_review_event WHERE learner_id = $1 ORDER BY target_kind, target_id, review_no """, target_learner_id, ) ) actual_event_rows = list( await conn.fetch( """ SELECT execution.*, practice_session.learner_feedback_enabled AS source_learner_feedback_enabled FROM app.calibration_transfer_execution_event execution JOIN app.sessions practice_session ON practice_session.id = execution.practice_session_id WHERE execution.learner_id = $1 ORDER BY execution.competency_id, execution.created_at, execution.execution_event_id """, target_learner_id, ) ) learner_feedback_snapshot_enabled = all( bool( _value( item, "source_learner_feedback_enabled", True, ) ) for item in (*histories, *assessments, *suites, *actual_event_rows) ) revisions_by_history: dict[UUID, list[dict[str, Any]]] = {} for row in revisions: revisions_by_history.setdefault( UUID(str(_value(row, "history_id"))), [] ).append(dict(row)) locks_by_history = { UUID(str(_value(row, "history_id"))): dict(row) for row in locks } observations_by_history = { UUID(str(_value(row, "history_id"))): dict(row) for row in observations } prediction_histories: list[dict[str, Any]] = [] for row in histories: item = _public_row(row) history_id = UUID(str(_value(row, "history_id"))) item["revisions"] = revisions_by_history.get(history_id, []) item["lock"] = locks_by_history.get(history_id) item["external_observation"] = observations_by_history.get(history_id) prediction_histories.append(item) trials_by_suite: dict[UUID, list[dict[str, Any]]] = {} for row in trials: trials_by_suite.setdefault( UUID(str(_value(row, "transfer_suite_record_id"))), [] ).append(dict(row)) assessments_by_suite: dict[UUID, list[dict[str, Any]]] = {} for row in transfer_assessments: assessments_by_suite.setdefault( UUID(str(_value(row, "transfer_suite_record_id"))), [] ).append(dict(row)) drift_by_suite: dict[UUID, list[dict[str, Any]]] = {} for row in drift_reports: drift_by_suite.setdefault( UUID(str(_value(row, "transfer_suite_record_id"))), [] ).append(dict(row)) suite_payloads: list[dict[str, Any]] = [] for row in suites: item = _public_row(row) suite_id = UUID(str(_value(row, "transfer_suite_record_id"))) item["trials"] = trials_by_suite.get(suite_id, []) item["assessments"] = assessments_by_suite.get(suite_id, []) item["drift_reports"] = drift_by_suite.get(suite_id, []) suite_payloads.append(item) actual_executions = tuple( _actual_execution_from_row(row) for row in actual_event_rows ) actual_assessments = assess_actual_transfer_executions(actual_executions) return { "learner_id": target_learner_id, "requested_view": requested_view, "clinical_claim_allowed": False, "_learner_feedback_snapshot_enabled": learner_feedback_snapshot_enabled, "prediction_histories": prediction_histories, "calibration_assessments": [_public_row(item) for item in assessments], "transfer_suites": suite_payloads, "teacher_reviews": [dict(item) for item in reviews], "actual_executions": [ item.model_dump(mode="python") for item in actual_executions ], "actual_transfer_assessments": [ item.model_dump(mode="python") for item in actual_assessments ], } __all__ = [ "CalibrationTransferConflictError", "CalibrationTransferNotFoundError", "CalibrationTransferStateError", "append_calibration_assessment", "append_performance_observation", "append_prediction_lock", "append_prediction_revision", "append_teacher_review", "append_transfer_suite", "append_actual_transfer_execution", "read_calibration_transfer", ]