G0~G8 성과·동맹 측정 OS 작업 일괄 고정

8월 7일까지 워킹트리에만 남아 있던 미커밋 작업을 커밋한다. 여러 사본
폴더(worktree·clone)에 흩어져 있던 중간 스냅샷을 정리하기 전에 원본을
git 이력으로 고정하는 것이 목적이다.

- contracts/routes/services: measurement, outcome_trajectory, rupture_repair,
  deliberate_practice, calibration_transfer, supervision_research,
  multimodal_alliance, continuous_improvement 계열 신규 모듈과 테스트
- infra/db/init: 07~16 마이그레이션(측정 기반~calibration transfer 실행)
- apps/web: 세션 리뷰 카드·관리 화면·E2E 스펙 추가
- docs/ops: G0~G8 라이브 통합·배포·롤백 증거 문서와 evidence JSON/PNG
- scripts: smoke·ledger·릴리스 에이전트·NAS 프리뷰 운영 스크립트

engine.public 로그 .bak과 apps/web/test-results 산출물은 커밋에서 제외했다.
This commit is contained in:
Yun Chan 2026-08-08 01:30:53 +09:00
parent 93dd8f82d7
commit 16e791e044
390 changed files with 243188 additions and 499 deletions

View file

@ -22,6 +22,8 @@ class RuntimeSchemaContract:
relations: tuple[str, ...]
columns: tuple[str, ...] = ()
policies: tuple[str, ...] = ()
triggers: tuple[str, ...] = ()
indexes: tuple[str, ...] = ()
REVIEW_SCHEMA_CONTRACT = RuntimeSchemaContract(
@ -64,6 +66,443 @@ NOTIFICATION_SCHEMA_CONTRACT = RuntimeSchemaContract(
),
)
MEASUREMENT_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="outcome/alliance measurement",
relations=(
"app.measurement_instrument",
"app.measurement_event",
"app.alliance_pulse",
"app.self_assessment",
"audit.alliance_pulse_status_event",
"audit.model_run",
"ds.benchmark_case",
"ds.benchmark_observation",
),
columns=(
"app.measurement_event.source_kind",
"app.measurement_event.perspective",
"app.measurement_event.instrument_id",
"app.measurement_event.model_run_id",
"app.measurement_event.supersedes_id",
"app.measurement_event.pulse_id",
"app.alliance_pulse.checkpoint",
"app.alliance_pulse.status",
"app.self_assessment.scores",
"audit.alliance_pulse_status_event.from_status",
"audit.alliance_pulse_status_event.to_status",
"audit.alliance_pulse_status_event.changed_at",
"audit.model_run.prompt_bundle_hash",
"audit.model_run.input_evidence_hash",
),
policies=(
"app.measurement_instrument.p_measurement_instrument_select",
"app.measurement_event.p_measurement_event_select",
"app.alliance_pulse.p_alliance_pulse_select",
"app.self_assessment.p_self_assessment_select",
"audit.alliance_pulse_status_event.p_alliance_pulse_status_event_select",
"audit.model_run.p_model_run_select",
"ds.benchmark_case.p_benchmark_case_select",
"ds.benchmark_observation.p_benchmark_observation_select",
),
triggers=(
"app.measurement_event.trg_measurement_event_append_only",
"app.alliance_pulse.trg_alliance_pulse_transition_guard",
"app.alliance_pulse.trg_alliance_pulse_delete_guard",
"app.alliance_pulse.trg_alliance_pulse_status_audit",
"app.self_assessment.trg_self_assessment_append_only",
"audit.alliance_pulse_status_event.trg_alliance_pulse_status_event_append_only",
"audit.model_run.trg_model_run_append_only",
),
)
OUTCOME_TRAJECTORY_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="longitudinal outcome trajectory",
relations=(
"ds.synthetic_outcome_arc",
"app.outcome_trajectory_revision",
"app.outcome_trajectory_observation",
"app.relationship_memory_event",
"app.relationship_memory_projection",
),
columns=(
"ds.synthetic_outcome_arc.data_classification",
"ds.synthetic_outcome_arc.clinical_claim_allowed",
"app.outcome_trajectory_revision.supersedes_revision_id",
"app.outcome_trajectory_revision.source_fingerprint",
"app.outcome_trajectory_revision.assessment",
"app.outcome_trajectory_observation.measurement_id",
"app.outcome_trajectory_observation.status",
"app.outcome_trajectory_observation.missing_reason",
"app.relationship_memory_event.resolves_event_id",
"app.relationship_memory_event.visible_to",
"app.relationship_memory_projection.ai_view",
),
policies=(
"ds.synthetic_outcome_arc.p_synthetic_outcome_arc_select",
"app.outcome_trajectory_revision.p_outcome_trajectory_revision_select",
"app.outcome_trajectory_observation.p_outcome_trajectory_observation_select",
"app.relationship_memory_event.p_relationship_memory_event_select",
"app.relationship_memory_projection.p_relationship_memory_projection_select",
),
triggers=(
"app.measurement_event.trg_outcome_submission_turn_ownership",
"ds.synthetic_outcome_arc.trg_synthetic_outcome_arc_append_only",
"app.outcome_trajectory_revision.trg_outcome_trajectory_revision_append_only",
"app.outcome_trajectory_observation.trg_outcome_trajectory_observation_append_only",
"app.relationship_memory_event.trg_relationship_memory_link",
"app.relationship_memory_event.trg_relationship_memory_event_append_only",
"app.relationship_memory_projection.trg_relationship_projection_view",
"app.relationship_memory_projection.trg_relationship_memory_projection_append_only",
),
indexes=("app.measurement_event.uq_measurement_event_outcome_submission_axis",),
)
RUPTURE_REPAIR_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="rupture and repair evidence ledger",
relations=(
"app.rupture_episode",
"app.rupture_observation_event",
"app.rupture_reconciliation_revision",
"app.rupture_safety_reference",
),
columns=(
"app.rupture_episode.case_id",
"app.rupture_episode.visible_to",
"app.rupture_observation_event.sequence_no",
"app.rupture_observation_event.evidence_turn_ids",
"app.rupture_observation_event.model_run_id",
"app.rupture_observation_event.supersedes_observation_id",
"app.rupture_reconciliation_revision.supersedes_revision_id",
"app.rupture_reconciliation_revision.disposition",
"app.rupture_safety_reference.safety_event_id",
),
policies=(
"app.rupture_episode.p_rupture_episode_select",
"app.rupture_episode.p_rupture_episode_insert",
"app.rupture_observation_event.p_rupture_observation_select",
"app.rupture_observation_event.p_rupture_observation_insert",
"app.rupture_reconciliation_revision.p_rupture_reconciliation_select",
"app.rupture_reconciliation_revision.p_rupture_reconciliation_insert",
"app.rupture_safety_reference.p_rupture_safety_select",
"app.rupture_safety_reference.p_rupture_safety_insert",
),
triggers=(
"app.rupture_episode.trg_rupture_episode_anchor",
"app.rupture_episode.trg_rupture_episode_append_only",
"app.rupture_observation_event.trg_rupture_observation_contract",
"app.rupture_observation_event.trg_rupture_observation_append_only",
"app.rupture_reconciliation_revision.trg_rupture_reconciliation_contract",
"app.rupture_reconciliation_revision.trg_rupture_reconciliation_append_only",
"app.rupture_safety_reference.trg_rupture_safety_contract",
"app.rupture_safety_reference.trg_rupture_safety_append_only",
),
indexes=("app.rupture_observation_event.uq_rupture_observation_episode_sequence",),
)
DELIBERATE_PRACTICE_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="deliberate practice evidence ledger",
relations=(
"app.practice_prescription_submission",
"app.practice_coaching_card",
"app.practice_prescription",
"app.practice_episode_submission",
"app.practice_attempt_evidence",
"app.competency_graph_snapshot",
"app.practice_curriculum_decision_event",
"app.practice_teacher_correction",
),
columns=(
"app.practice_prescription_submission.content_hash",
"app.practice_coaching_card.evidence_turn_ids",
"app.practice_coaching_card.uncertainty",
"app.practice_prescription.activity_mode",
"app.practice_prescription.scenario_novelty",
"app.practice_episode_submission.mastery_allowed",
"app.practice_episode_submission.mastery_blockers",
"app.practice_attempt_evidence.client_response",
"app.practice_attempt_evidence.utterance_template_id",
"app.competency_graph_snapshot.supersedes_snapshot_id",
"app.practice_curriculum_decision_event.selected_prescription_record_id",
"app.practice_teacher_correction.supersedes_correction_id",
),
policies=(
"app.practice_prescription_submission.p_practice_prescription_submission_select",
"app.practice_prescription_submission.p_practice_prescription_submission_insert",
"app.practice_teacher_correction.p_practice_teacher_correction_select",
"app.practice_teacher_correction.p_practice_teacher_correction_insert",
),
triggers=(
"app.practice_episode_submission.trg_practice_episode_transfer_gate",
"app.practice_attempt_evidence.trg_practice_attempt_contract",
"app.competency_graph_snapshot.trg_competency_snapshot_chain",
"app.practice_curriculum_decision_event.trg_practice_curriculum_decision_contract",
"app.practice_teacher_correction.trg_practice_teacher_correction_contract",
),
indexes=(
"app.practice_prescription.uq_practice_prescription_record_learner",
"app.practice_attempt_evidence.idx_practice_attempt_episode_sequence",
"app.competency_graph_snapshot.idx_competency_graph_snapshot_latest",
"app.practice_teacher_correction.idx_practice_teacher_correction_attempt",
),
)
CALIBRATION_TRANSFER_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="calibration mirror and unseen transfer ledger",
relations=(
"app.calibration_prediction_history",
"app.calibration_prediction_revision",
"app.calibration_prediction_lock",
"app.calibration_performance_observation",
"app.calibration_assessment_snapshot",
"app.calibration_metacognitive_prescription",
"app.calibration_transfer_suite",
"app.calibration_transfer_trial",
"app.calibration_transfer_assessment",
"app.calibration_subgroup_drift_report",
"app.calibration_teacher_review_event",
"app.calibration_transfer_execution_event",
),
columns=(
"app.calibration_prediction_revision.supersedes_prediction_revision_id",
"app.calibration_prediction_revision.predicted_success_probability",
"app.calibration_prediction_lock.locked_sequence",
"app.calibration_performance_observation.revealed_sequence",
"app.calibration_performance_observation.uncertainty",
"app.calibration_assessment_snapshot.assessment_payload",
"app.calibration_metacognitive_prescription.prescription_payload",
"app.calibration_transfer_suite.clinical_claim_allowed",
"app.calibration_transfer_trial.relationship_style",
"app.calibration_transfer_trial.phrase_family_id",
"app.calibration_transfer_assessment.assessment_payload",
"app.calibration_subgroup_drift_report.data_classification",
"app.calibration_teacher_review_event.supersedes_review_id",
"app.calibration_transfer_execution_event.original_transfer_trial_record_id",
"app.calibration_transfer_execution_event.practice_session_id",
"app.calibration_transfer_execution_event.normalized_evaluator_labels",
"app.calibration_transfer_execution_event.source_kind",
"app.calibration_transfer_execution_event.perspective",
"app.calibration_transfer_execution_event.model_run_id",
"app.calibration_transfer_execution_event.instrument_id",
"app.calibration_transfer_execution_event.instrument_version",
"app.calibration_transfer_execution_event.observer_version",
"app.calibration_transfer_execution_event.evidence_turn_ids",
),
policies=(
"app.calibration_teacher_review_event.p_calibration_teacher_review_event_select",
"app.calibration_teacher_review_event.p_calibration_teacher_review_event_insert",
"app.calibration_transfer_execution_event.p_calibration_transfer_execution_event_select",
"app.calibration_transfer_execution_event.p_calibration_transfer_execution_event_insert",
),
triggers=(
"app.calibration_prediction_revision.trg_calibration_prediction_revision_contract",
"app.calibration_prediction_lock.trg_calibration_prediction_lock_contract",
"app.calibration_performance_observation.trg_calibration_observation_reveal_contract",
"app.calibration_assessment_snapshot.trg_calibration_assessment_chain",
"app.calibration_transfer_assessment.trg_calibration_transfer_assessment_contract",
"app.calibration_subgroup_drift_report.trg_calibration_subgroup_drift_contract",
"app.calibration_teacher_review_event.trg_calibration_teacher_review_contract",
"app.calibration_transfer_execution_event.trg_calibration_transfer_execution_contract",
"app.calibration_transfer_execution_event.trg_calibration_transfer_execution_append_only",
),
indexes=(
"app.calibration_prediction_revision.idx_calibration_prediction_revision_latest",
"app.calibration_performance_observation.idx_calibration_observation_learner_competency",
"app.calibration_transfer_trial.idx_calibration_transfer_trial_suite_competency",
"app.calibration_teacher_review_event.idx_calibration_teacher_review_target",
"app.calibration_transfer_execution_event.idx_calibration_transfer_execution_learner_competency",
"app.calibration_transfer_execution_event.idx_calibration_transfer_execution_trial",
),
)
SUPERVISION_RESEARCH_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="supervision and research evidence ledger",
relations=(
"app.supervision_evidence_pointer",
"app.supervision_attention_snapshot",
"app.supervision_attention_item",
"app.supervision_attention_reason",
"app.supervision_teacher_ai_disagreement",
"app.supervision_calibration_dataset_row",
"audit.supervision_teacher_event",
"app.supervision_curriculum_gap_snapshot",
"app.supervision_evaluation_batch",
"app.supervision_evaluation_observation",
"app.supervision_drift_report",
"app.supervision_drift_subgroup_metric",
"app.supervision_phase3_manifest",
"app.supervision_phase3_artifact",
),
columns=(
"app.supervision_evidence_pointer.consumer_view",
"app.supervision_evidence_pointer.content_hash",
"app.supervision_attention_item.evidence_pointer_ids",
"app.supervision_attention_item.drilldown_routes",
"app.supervision_teacher_ai_disagreement.raw_transcript_included",
"app.supervision_calibration_dataset_row.row_hash",
"audit.supervision_teacher_event.content_hash",
"app.supervision_curriculum_gap_snapshot.status",
"app.supervision_evaluation_batch.prompt_version",
"app.supervision_drift_report.status",
"app.supervision_phase3_manifest.artifact_count",
"app.supervision_phase3_artifact.source_pointer_id",
),
policies=(
"app.supervision_evidence_pointer.p_supervision_evidence_pointer_select",
"app.supervision_evidence_pointer.p_supervision_evidence_pointer_insert",
"app.supervision_attention_snapshot.p_supervision_attention_snapshot_select",
"app.supervision_attention_snapshot.p_supervision_attention_snapshot_insert",
"app.supervision_attention_item.p_supervision_attention_item_select",
"app.supervision_attention_item.p_supervision_attention_item_insert",
"app.supervision_curriculum_gap_snapshot.p_supervision_curriculum_gap_select",
"app.supervision_curriculum_gap_snapshot.p_supervision_curriculum_gap_insert",
"app.supervision_teacher_ai_disagreement.p_supervision_teacher_ai_disagreement_insert",
"app.supervision_calibration_dataset_row.p_supervision_calibration_dataset_row_insert",
"audit.supervision_teacher_event.p_supervision_teacher_event_select",
"audit.supervision_teacher_event.p_supervision_teacher_event_insert",
),
triggers=(
"app.supervision_evidence_pointer.trg_supervision_evidence_pointer_contract",
"app.supervision_attention_item.trg_supervision_attention_item_contract",
"app.supervision_attention_reason.trg_supervision_attention_reason_contract",
"app.supervision_teacher_ai_disagreement.trg_supervision_teacher_ai_actor",
"audit.supervision_teacher_event.trg_supervision_teacher_event_append_only",
"audit.supervision_teacher_event.trg_supervision_teacher_event_pointer_array",
),
)
CONTINUOUS_IMPROVEMENT_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="continuous improvement approval ledger",
relations=(
"app.ci_ingestion_submission",
"app.ci_source_artifact",
"app.ci_agentic_job",
"app.ci_content_pipeline",
"app.ci_red_team_review",
"app.ci_red_team_finding",
"app.ci_content_benchmark",
"app.ci_content_qualification",
"app.ci_gate_artifact",
"app.ci_model_calibration_snapshot",
"app.ci_model_change_gate",
"app.ci_release_gate",
"audit.ci_human_approval_event",
"app.ci_catalog_entry",
"audit.ci_lifecycle_event",
"app.ci_operational_incident",
"app.ci_regression_dag_node",
),
columns=(
"app.ci_ingestion_submission.data_classification",
"app.ci_agentic_job.data_classification",
"app.ci_agentic_job.status",
"app.ci_content_pipeline.state",
"app.ci_content_pipeline.draft_payload",
"app.ci_content_qualification.gate_state",
"app.ci_gate_artifact.artifact_kind",
"app.ci_model_change_gate.gate_decision",
"app.ci_model_change_gate.state",
"app.ci_release_gate.state",
"audit.ci_human_approval_event.decision",
"app.ci_catalog_entry.approval_event_id",
"audit.ci_lifecycle_event.event_status",
"audit.ci_lifecycle_event.executor_receipt_id",
"audit.ci_lifecycle_event.executor_evidence_refs",
"app.ci_operational_incident.pii_included",
"app.ci_regression_dag_node.depends_on_record_ids",
),
policies=(
"app.ci_ingestion_submission.p_ci_ingestion_submission_admin_insert",
"app.ci_agentic_job.p_ci_agentic_job_select",
"app.ci_agentic_job.p_ci_agentic_job_insert",
"app.ci_agentic_job.p_ci_agentic_job_update",
"app.ci_catalog_entry.p_ci_catalog_entry_select",
"app.ci_catalog_entry.p_ci_catalog_entry_insert",
"audit.ci_human_approval_event.p_ci_human_approval_select",
"audit.ci_human_approval_event.p_ci_human_approval_insert",
"audit.ci_lifecycle_event.p_ci_lifecycle_select",
"audit.ci_lifecycle_event.p_ci_lifecycle_monitor_insert",
"audit.ci_lifecycle_event.p_ci_lifecycle_admin_insert",
),
triggers=(
"app.ci_content_pipeline.trg_ci_content_pipeline_sources",
"app.ci_agentic_job.trg_ci_agentic_job_update_contract",
"app.ci_content_qualification.trg_ci_content_qualification_sources",
"app.ci_model_change_gate.trg_ci_model_gate_artifacts",
"app.ci_release_gate.trg_ci_release_gate_artifacts",
"app.ci_regression_dag_node.trg_ci_dag_dependencies",
"app.ci_red_team_review.trg_ci_red_team_review_contract",
"app.ci_red_team_finding.trg_ci_red_team_finding_contract",
"audit.ci_human_approval_event.trg_ci_human_approval_contract",
"app.ci_catalog_entry.trg_ci_catalog_approval",
"audit.ci_lifecycle_event.trg_ci_lifecycle_contract",
"app.ci_model_change_gate.trg_ci_model_snapshot_contract",
),
indexes=(
"app.ci_agentic_job.idx_ci_agentic_job_ready",
),
)
MULTIMODAL_ALLIANCE_SCHEMA_CONTRACT = RuntimeSchemaContract(
component="multimodal alliance consent and evidence ledger",
relations=(
"app.multimodal_ingestion_request",
"app.multimodal_consent_snapshot",
"app.multimodal_audio_asset",
"app.multimodal_audio_timeline",
"app.multimodal_word_timestamp",
"app.multimodal_voice_event",
"app.multimodal_axis_measurement",
"app.multimodal_fusion_decision",
"app.multimodal_deletion_request",
"audit.multimodal_deletion_tombstone",
),
columns=(
"app.multimodal_ingestion_request.content_hash",
"app.multimodal_consent_snapshot.consent_status",
"app.multimodal_audio_asset.retained_until",
"app.multimodal_audio_timeline.clock_version",
"app.multimodal_word_timestamp.token_hash",
"app.multimodal_voice_event.claim_scope",
"app.multimodal_axis_measurement.source_kind",
"app.multimodal_fusion_decision.fusion_applied",
"app.multimodal_fusion_decision.incremental_gain",
"app.multimodal_deletion_request.scopes",
"audit.multimodal_deletion_tombstone.deletion_proof",
),
policies=(
"app.multimodal_audio_asset.p_multimodal_audio_asset_select",
"app.multimodal_ingestion_request.p_multimodal_human_ingestion_insert",
"app.multimodal_consent_snapshot.p_multimodal_consent_insert",
"app.multimodal_deletion_request.p_multimodal_deletion_request_insert",
"audit.multimodal_deletion_tombstone.p_multimodal_tombstone_select",
"audit.multimodal_deletion_tombstone.p_multimodal_tombstone_insert",
),
triggers=(
"app.multimodal_consent_snapshot.trg_multimodal_consent_sequence",
"app.multimodal_audio_asset.trg_multimodal_audio_consent",
"app.multimodal_audio_timeline.trg_multimodal_timeline_consent",
"app.multimodal_word_timestamp.trg_multimodal_word_clock",
"app.multimodal_voice_event.trg_multimodal_event_clock",
"app.multimodal_fusion_decision.trg_multimodal_fusion_contract",
"audit.multimodal_deletion_tombstone.trg_multimodal_deletion_tombstone_append_only",
),
indexes=(
"app.multimodal_consent_snapshot.idx_multimodal_consent_latest",
"app.multimodal_audio_timeline.idx_multimodal_timeline_session",
"app.multimodal_word_timestamp.idx_multimodal_word_clock",
"app.multimodal_voice_event.idx_multimodal_event_clock",
"app.multimodal_axis_measurement.idx_multimodal_measurement_session",
"app.multimodal_deletion_request.idx_multimodal_deletion_pending",
),
)
async def schema_contract_ready(
conn: SchemaConnection,
@ -98,11 +537,38 @@ async def schema_contract_ready(
AND p.tablename = split_part(required.qualified_name, '.', 2)
AND p.policyname = split_part(required.qualified_name, '.', 3)
)
)
AND NOT EXISTS (
SELECT 1
FROM unnest($4::text[]) AS required(qualified_name)
WHERE NOT EXISTS (
SELECT 1
FROM pg_trigger t
JOIN pg_class c ON c.oid = t.tgrelid
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = split_part(required.qualified_name, '.', 1)
AND c.relname = split_part(required.qualified_name, '.', 2)
AND t.tgname = split_part(required.qualified_name, '.', 3)
AND NOT t.tgisinternal
)
)
AND NOT EXISTS (
SELECT 1
FROM unnest($5::text[]) AS required(qualified_name)
WHERE NOT EXISTS (
SELECT 1
FROM pg_indexes i
WHERE i.schemaname = split_part(required.qualified_name, '.', 1)
AND i.tablename = split_part(required.qualified_name, '.', 2)
AND i.indexname = split_part(required.qualified_name, '.', 3)
)
) AS ready
""",
list(contract.relations),
list(contract.columns),
list(contract.policies),
list(contract.triggers),
list(contract.indexes),
)
return bool(row and row["ready"])